Improve signature of DOM APIs (#43652)

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

This improves the signature of our existing DOM APIs in 2 ways:
1. It replaces the use of `tuples` in `DOM.{h,cpp}` with safer structs.
2. It removes some unnecessary optionals from the API, returning the default values from the C++ API directly when appropriate.

It still preserves the use of tuples in the native module because objects are not properly supported in the codegen.

Changelog: [internal]

Reviewed By: NickGerleman

Differential Revision: D55316654

fbshipit-source-id: 16ce5ef62ca427cdcd6b9757d77db040e0ccc8b1
This commit is contained in:
Rubén Norte
2024-03-26 08:39:49 -07:00
committed by Facebook GitHub Bot
parent e69f6755c8
commit 3a0bf7d89e
10 changed files with 271 additions and 346 deletions
@@ -11,7 +11,6 @@
#include <react/renderer/uimanager/PointerEventsProcessor.h>
#include <react/renderer/uimanager/UIManager.h>
#include <react/renderer/uimanager/UIManagerBinding.h>
#include <optional>
#ifdef RN_DISABLE_OSS_PLUGIN_HEADER
#include "Plugins.h"
@@ -64,42 +63,36 @@ namespace facebook::react {
NativeDOM::NativeDOM(std::shared_ptr<CallInvoker> jsInvoker)
: NativeDOMCxxSpec(std::move(jsInvoker)) {}
std::optional<jsi::Value> NativeDOM::getParentNode(
jsi::Value NativeDOM::getParentNode(
jsi::Runtime& rt,
jsi::Value shadowNodeValue) {
auto shadowNode = shadowNodeFromValue(rt, shadowNodeValue);
auto currentRevision =
getCurrentShadowTreeRevision(rt, shadowNode->getSurfaceId());
if (currentRevision == nullptr) {
return std::nullopt;
return jsi::Value::undefined();
}
auto parentShadowNode = dom::getParentNode(currentRevision, *shadowNode);
if (parentShadowNode == nullptr) {
return std::nullopt;
return jsi::Value::undefined();
}
return parentShadowNode->getInstanceHandle(rt);
}
std::optional<std::vector<jsi::Value>> NativeDOM::getChildNodes(
std::vector<jsi::Value> NativeDOM::getChildNodes(
jsi::Runtime& rt,
jsi::Value shadowNodeValue) {
auto shadowNode = shadowNodeFromValue(rt, shadowNodeValue);
auto currentRevision =
getCurrentShadowTreeRevision(rt, shadowNode->getSurfaceId());
if (currentRevision == nullptr) {
return std::nullopt;
return std::vector<jsi::Value>{};
}
auto childNodes = dom::getChildNodes(currentRevision, *shadowNode);
// There's no version of this node in the current shadow tree
if (!childNodes) {
return std::nullopt;
}
return getArrayOfInstanceHandlesFromShadowNodes(childNodes.value(), rt);
return getArrayOfInstanceHandlesFromShadowNodes(childNodes, rt);
}
bool NativeDOM::isConnected(jsi::Runtime& rt, jsi::Value shadowNodeValue) {
@@ -142,11 +135,11 @@ std::string NativeDOM::getTextContent(
return dom::getTextContent(currentRevision, *shadowNode);
}
std::optional<std::tuple<
std::tuple<
/* x: */ double,
/* y: */ double,
/* width: */ double,
/* height: */ double>>
/* height: */ double>
NativeDOM::getBoundingClientRect(
jsi::Runtime& rt,
jsi::Value shadowNodeValue,
@@ -155,89 +148,93 @@ NativeDOM::getBoundingClientRect(
auto currentRevision =
getCurrentShadowTreeRevision(rt, shadowNode->getSurfaceId());
if (currentRevision == nullptr) {
return std::nullopt;
return {0, 0, 0, 0};
}
return dom::getBoundingClientRect(
auto domRect = dom::getBoundingClientRect(
currentRevision, *shadowNode, includeTransform);
return std::tuple{domRect.x, domRect.y, domRect.width, domRect.height};
}
std::optional<std::tuple<
std::tuple<
/* offsetParent: */ jsi::Value,
/* top: */ double,
/* left: */ double>>
/* left: */ double>
NativeDOM::getOffset(jsi::Runtime& rt, jsi::Value shadowNodeValue) {
auto shadowNode = shadowNodeFromValue(rt, shadowNodeValue);
auto currentRevision =
getCurrentShadowTreeRevision(rt, shadowNode->getSurfaceId());
if (currentRevision == nullptr) {
return std::nullopt;
return {jsi::Value::undefined(), 0, 0};
}
auto offset = dom::getOffset(currentRevision, *shadowNode);
if (!offset) {
return std::nullopt;
}
auto& offsetValue = offset.value();
auto domOffset = dom::getOffset(currentRevision, *shadowNode);
return std::tuple{
std::get<0>(offsetValue)->getInstanceHandle(rt),
std::get<1>(offsetValue),
std::get<2>(offsetValue)};
domOffset.offsetParent == nullptr
? jsi::Value::undefined()
: domOffset.offsetParent->getInstanceHandle(rt),
domOffset.top,
domOffset.left};
}
std::optional<std::tuple</* scrollLeft: */ double, /* scrollTop: */ double>>
std::tuple</* scrollLeft: */ double, /* scrollTop: */ double>
NativeDOM::getScrollPosition(jsi::Runtime& rt, jsi::Value shadowNodeValue) {
auto shadowNode = shadowNodeFromValue(rt, shadowNodeValue);
auto currentRevision =
getCurrentShadowTreeRevision(rt, shadowNode->getSurfaceId());
if (currentRevision == nullptr) {
return std::nullopt;
return {0, 0};
}
return dom::getScrollPosition(currentRevision, *shadowNode);
auto domPoint = dom::getScrollPosition(currentRevision, *shadowNode);
return std::tuple{domPoint.x, domPoint.y};
}
std::optional<std::tuple</* scrollWidth: */ int, /* scrollHeight */ int>>
std::tuple</* scrollWidth: */ int, /* scrollHeight */ int>
NativeDOM::getScrollSize(jsi::Runtime& rt, jsi::Value shadowNodeValue) {
auto shadowNode = shadowNodeFromValue(rt, shadowNodeValue);
auto currentRevision =
getCurrentShadowTreeRevision(rt, shadowNode->getSurfaceId());
if (currentRevision == nullptr) {
return std::nullopt;
return {0, 0};
}
return dom::getScrollSize(currentRevision, *shadowNode);
auto scrollSize = dom::getScrollSize(currentRevision, *shadowNode);
return std::tuple{scrollSize.width, scrollSize.height};
}
std::optional<std::tuple</* width: */ int, /* height: */ int>>
NativeDOM::getInnerSize(jsi::Runtime& rt, jsi::Value shadowNodeValue) {
std::tuple</* width: */ int, /* height: */ int> NativeDOM::getInnerSize(
jsi::Runtime& rt,
jsi::Value shadowNodeValue) {
auto shadowNode = shadowNodeFromValue(rt, shadowNodeValue);
auto currentRevision =
getCurrentShadowTreeRevision(rt, shadowNode->getSurfaceId());
if (currentRevision == nullptr) {
return std::nullopt;
return {0, 0};
}
return dom::getInnerSize(currentRevision, *shadowNode);
auto innerSize = dom::getInnerSize(currentRevision, *shadowNode);
return std::tuple{innerSize.width, innerSize.height};
}
std::optional<std::tuple<
std::tuple<
/* topWidth: */ int,
/* rightWidth: */ int,
/* bottomWidth: */ int,
/* leftWidth: */ int>>
NativeDOM::getBorderSize(jsi::Runtime& rt, jsi::Value shadowNodeValue) {
/* leftWidth: */ int>
NativeDOM::getBorderWidth(jsi::Runtime& rt, jsi::Value shadowNodeValue) {
auto shadowNode = shadowNodeFromValue(rt, shadowNodeValue);
auto currentRevision =
getCurrentShadowTreeRevision(rt, shadowNode->getSurfaceId());
if (currentRevision == nullptr) {
return std::nullopt;
return {0, 0, 0, 0};
}
return dom::getBorderSize(currentRevision, *shadowNode);
auto borderWidth = dom::getBorderWidth(currentRevision, *shadowNode);
return std::tuple{
borderWidth.top, borderWidth.right, borderWidth.bottom, borderWidth.left};
}
std::string NativeDOM::getTagName(
@@ -23,11 +23,9 @@ class NativeDOM : public NativeDOMCxxSpec<NativeDOM> {
public:
NativeDOM(std::shared_ptr<CallInvoker> jsInvoker);
std::optional<jsi::Value> getParentNode(
jsi::Runtime& rt,
jsi::Value shadowNodeValue);
jsi::Value getParentNode(jsi::Runtime& rt, jsi::Value shadowNodeValue);
std::optional<std::vector<jsi::Value>> getChildNodes(
std::vector<jsi::Value> getChildNodes(
jsi::Runtime& rt,
jsi::Value shadowNodeValue);
@@ -40,38 +38,39 @@ class NativeDOM : public NativeDOMCxxSpec<NativeDOM> {
std::string getTextContent(jsi::Runtime& rt, jsi::Value shadowNodeValue);
std::optional<std::tuple<
std::tuple<
/* x: */ double,
/* y: */ double,
/* width: */ double,
/* height: */ double>>
/* height: */ double>
getBoundingClientRect(
jsi::Runtime& rt,
jsi::Value shadowNodeValue,
bool includeTransform);
std::optional<std::tuple<
std::tuple<
/* offsetParent: */ jsi::Value,
/* top: */ double,
/* left: */ double>>
/* left: */ double>
getOffset(jsi::Runtime& rt, jsi::Value shadowNodeValue);
std::optional<std::tuple</* scrollLeft: */ double, /* scrollTop: */ double>>
std::tuple</* scrollLeft: */ double, /* scrollTop: */ double>
getScrollPosition(jsi::Runtime& rt, jsi::Value shadowNodeValue);
std::optional<std::tuple</* scrollWidth: */ int, /* scrollHeight */ int>>
getScrollSize(jsi::Runtime& rt, jsi::Value shadowNodeValue);
std::optional<std::tuple</* width: */ int, /* height: */ int>> getInnerSize(
std::tuple</* scrollWidth: */ int, /* scrollHeight */ int> getScrollSize(
jsi::Runtime& rt,
jsi::Value shadowNodeValue);
std::optional<std::tuple<
std::tuple</* width: */ int, /* height: */ int> getInnerSize(
jsi::Runtime& rt,
jsi::Value shadowNodeValue);
std::tuple<
/* topWidth: */ int,
/* rightWidth: */ int,
/* bottomWidth: */ int,
/* leftWidth: */ int>>
getBorderSize(jsi::Runtime& rt, jsi::Value shadowNodeValue);
/* leftWidth: */ int>
getBorderWidth(jsi::Runtime& rt, jsi::Value shadowNodeValue);
std::string getTagName(jsi::Runtime& rt, jsi::Value shadowNodeValue);
@@ -11,6 +11,7 @@
#include <react/renderer/graphics/Point.h>
#include <react/renderer/graphics/Rect.h>
#include <react/renderer/graphics/Size.h>
#include <cmath>
namespace {
@@ -170,13 +171,13 @@ ShadowNode::Shared getParentNode(
return getParentShadowNodeInRevision(currentRevision, shadowNode);
}
std::optional<std::vector<ShadowNode::Shared>> getChildNodes(
std::vector<ShadowNode::Shared> getChildNodes(
const RootShadowNode::Shared& currentRevision,
const ShadowNode& shadowNode) {
auto shadowNodeInCurrentRevision =
getShadowNodeInRevision(currentRevision, shadowNode);
if (shadowNodeInCurrentRevision == nullptr) {
return std::nullopt;
return {};
}
return shadowNodeInCurrentRevision->getChildren();
@@ -251,20 +252,14 @@ std::string getTextContent(
return result;
}
std::optional<std::tuple<
/* x: */ double,
/* y: */ double,
/* width: */ double,
/* height: */
double>>
getBoundingClientRect(
DOMRect getBoundingClientRect(
const RootShadowNode::Shared& currentRevision,
const ShadowNode& shadowNode,
bool includeTransform) {
auto shadowNodeInCurrentRevision =
getShadowNodeInRevision(currentRevision, shadowNode);
if (shadowNodeInCurrentRevision == nullptr) {
return std::nullopt;
return DOMRect{};
}
auto layoutMetrics = getRelativeLayoutMetrics(
@@ -273,20 +268,18 @@ getBoundingClientRect(
{.includeTransform = includeTransform, .includeViewportOffset = true});
if (layoutMetrics == EmptyLayoutMetrics) {
return std::nullopt;
return DOMRect{};
}
auto frame = layoutMetrics.frame;
return std::tuple{
frame.origin.x, frame.origin.y, frame.size.width, frame.size.height};
return DOMRect{
.x = frame.origin.x,
.y = frame.origin.y,
.width = frame.size.width,
.height = frame.size.height};
}
std::optional<std::tuple<
/* offsetParent: */ ShadowNode::Shared,
/* top: */ double,
/* left: */
double>>
getOffset(
DOMOffset getOffset(
const RootShadowNode::Shared& currentRevision,
const ShadowNode& shadowNode) {
auto shadowNodeInCurrentRevision =
@@ -298,7 +291,7 @@ getOffset(
// root node
if (shadowNodeInCurrentRevision == nullptr ||
positionedAncestorOfShadowNodeInCurrentRevision == nullptr) {
return std::nullopt;
return DOMOffset{};
}
// If the node is not displayed (itself or any of its ancestors has
@@ -306,7 +299,7 @@ getOffset(
auto shadowNodeLayoutMetricsRelativeToRoot = getRelativeLayoutMetrics(
*currentRevision, shadowNode, {.includeTransform = false});
if (shadowNodeLayoutMetricsRelativeToRoot == EmptyLayoutMetrics) {
return std::nullopt;
return DOMOffset{};
}
auto positionedAncestorLayoutMetricsRelativeToRoot = getRelativeLayoutMetrics(
@@ -314,7 +307,7 @@ getOffset(
*positionedAncestorOfShadowNodeInCurrentRevision,
{.includeTransform = false});
if (positionedAncestorLayoutMetricsRelativeToRoot == EmptyLayoutMetrics) {
return std::nullopt;
return DOMOffset{};
}
auto shadowNodeOriginRelativeToRoot =
@@ -331,18 +324,19 @@ getOffset(
positionedAncestorOriginRelativeToRoot.x -
positionedAncestorLayoutMetricsRelativeToRoot.borderWidth.left;
return std::tuple{
positionedAncestorOfShadowNodeInCurrentRevision, offsetTop, offsetLeft};
return DOMOffset{
.offsetParent = positionedAncestorOfShadowNodeInCurrentRevision,
.top = offsetTop,
.left = offsetLeft};
}
std::optional<std::tuple</* scrollLeft: */ double, /* scrollTop: */ double>>
getScrollPosition(
DOMPoint getScrollPosition(
const RootShadowNode::Shared& currentRevision,
const ShadowNode& shadowNode) {
auto shadowNodeInCurrentRevision =
getShadowNodeInRevision(currentRevision, shadowNode);
if (shadowNodeInCurrentRevision == nullptr) {
return std::nullopt;
return DOMPoint{};
}
// If the node is not displayed (itself or any of its ancestors has
@@ -353,31 +347,30 @@ getScrollPosition(
{.includeTransform = true});
if (layoutMetrics == EmptyLayoutMetrics) {
return std::nullopt;
return DOMPoint{};
}
auto layoutableShadowNode = dynamic_cast<LayoutableShadowNode const*>(
shadowNodeInCurrentRevision.get());
// This should never happen
if (layoutableShadowNode == nullptr) {
return std::nullopt;
return DOMPoint{};
}
auto scrollPosition = layoutableShadowNode->getContentOriginOffset();
return std::tuple{
scrollPosition.x == 0 ? 0 : -scrollPosition.x,
scrollPosition.y == 0 ? 0 : -scrollPosition.y};
return DOMPoint{
.x = scrollPosition.x == 0 ? 0 : -scrollPosition.x,
.y = scrollPosition.y == 0 ? 0 : -scrollPosition.y};
}
std::optional<std::tuple</* scrollWidth: */ int, /* scrollHeight */ int>>
getScrollSize(
DOMSizeRounded getScrollSize(
const RootShadowNode::Shared& currentRevision,
const ShadowNode& shadowNode) {
auto shadowNodeInCurrentRevision =
getShadowNodeInRevision(currentRevision, shadowNode);
if (shadowNodeInCurrentRevision == nullptr) {
return std::nullopt;
return DOMSizeRounded{};
}
// If the node is not displayed (itself or any of its ancestors has
@@ -389,31 +382,32 @@ getScrollSize(
if (layoutMetrics == EmptyLayoutMetrics ||
layoutMetrics.displayType == DisplayType::Inline) {
return std::nullopt;
return DOMSizeRounded{};
}
auto layoutableShadowNode = dynamic_cast<YogaLayoutableShadowNode const*>(
shadowNodeInCurrentRevision.get());
// This should never happen
if (layoutableShadowNode == nullptr) {
return std::nullopt;
return DOMSizeRounded{};
}
Size scrollSize = getScrollableContentBounds(
layoutableShadowNode->getContentBounds(), layoutMetrics)
.size;
return std::tuple{
std::round(scrollSize.width), std::round(scrollSize.height)};
return DOMSizeRounded{
.width = static_cast<int>(std::round(scrollSize.width)),
.height = static_cast<int>(std::round(scrollSize.height))};
}
std::optional<std::tuple</* width: */ int, /* height: */ int>> getInnerSize(
DOMSizeRounded getInnerSize(
const RootShadowNode::Shared& currentRevision,
const ShadowNode& shadowNode) {
auto shadowNodeInCurrentRevision =
getShadowNodeInRevision(currentRevision, shadowNode);
if (shadowNodeInCurrentRevision == nullptr) {
return std::nullopt;
return DOMSizeRounded{};
}
// If the node is not displayed (itself or any of its ancestors has
@@ -425,29 +419,23 @@ std::optional<std::tuple</* width: */ int, /* height: */ int>> getInnerSize(
if (layoutMetrics == EmptyLayoutMetrics ||
layoutMetrics.displayType == DisplayType::Inline) {
return std::nullopt;
return DOMSizeRounded{};
}
auto paddingFrame = layoutMetrics.getPaddingFrame();
return std::tuple{
std::round(paddingFrame.size.width),
std::round(paddingFrame.size.height)};
return DOMSizeRounded{
.width = static_cast<int>(std::round(paddingFrame.size.width)),
.height = static_cast<int>(std::round(paddingFrame.size.height))};
}
std::optional<std::tuple<
/* topWidth: */ int,
/* rightWidth: */ int,
/* bottomWidth: */ int,
/* leftWidth: */
int>>
getBorderSize(
DOMBorderWidthRounded getBorderWidth(
const RootShadowNode::Shared& currentRevision,
const ShadowNode& shadowNode) {
auto shadowNodeInCurrentRevision =
getShadowNodeInRevision(currentRevision, shadowNode);
if (shadowNodeInCurrentRevision == nullptr) {
return std::nullopt;
return DOMBorderWidthRounded{};
}
// If the node is not displayed (itself or any of its ancestors has
@@ -459,14 +447,14 @@ getBorderSize(
if (layoutMetrics == EmptyLayoutMetrics ||
layoutMetrics.displayType == DisplayType::Inline) {
return std::nullopt;
return DOMBorderWidthRounded{};
}
return std::tuple{
std::round(layoutMetrics.borderWidth.top),
std::round(layoutMetrics.borderWidth.right),
std::round(layoutMetrics.borderWidth.bottom),
std::round(layoutMetrics.borderWidth.left)};
return DOMBorderWidthRounded{
.top = static_cast<int>(std::round(layoutMetrics.borderWidth.top)),
.right = static_cast<int>(std::round(layoutMetrics.borderWidth.right)),
.bottom = static_cast<int>(std::round(layoutMetrics.borderWidth.bottom)),
.left = static_cast<int>(std::round(layoutMetrics.borderWidth.left))};
}
std::string getTagName(const ShadowNode& shadowNode) {
@@ -486,20 +474,13 @@ std::string getTagName(const ShadowNode& shadowNode) {
return canonicalComponentName;
}
std::optional<std::tuple<
/* x: */ double,
/* y: */ double,
/* width: */ double,
/* height: */ double,
/* pageX: */ double,
/* pageY: */ double>>
measure(
RNMeasureRect measure(
const RootShadowNode::Shared& currentRevision,
const ShadowNode& shadowNode) {
auto shadowNodeInCurrentRevision =
getShadowNodeInRevision(currentRevision, shadowNode);
if (shadowNodeInCurrentRevision == nullptr) {
return std::nullopt;
return RNMeasureRect{};
}
auto layoutMetrics = getRelativeLayoutMetrics(
@@ -508,7 +489,7 @@ measure(
{.includeTransform = true, .includeViewportOffset = false});
if (layoutMetrics == EmptyLayoutMetrics) {
return std::nullopt;
return RNMeasureRect{};
}
auto layoutableShadowNode = dynamic_cast<const LayoutableShadowNode*>(
@@ -519,27 +500,22 @@ measure(
auto frame = layoutMetrics.frame;
return std::tuple{
(double)originRelativeToParent.x,
(double)originRelativeToParent.y,
(double)frame.size.width,
(double)frame.size.height,
(double)frame.origin.x,
(double)frame.origin.y};
return RNMeasureRect{
.x = originRelativeToParent.x,
.y = originRelativeToParent.y,
.width = frame.size.width,
.height = frame.size.height,
.pageX = frame.origin.x,
.pageY = frame.origin.y};
}
std::optional<std::tuple<
/* x: */ double,
/* y: */ double,
/* width: */ double,
/* height: */ double>>
measureInWindow(
DOMRect measureInWindow(
const RootShadowNode::Shared& currentRevision,
const ShadowNode& shadowNode) {
auto shadowNodeInCurrentRevision =
getShadowNodeInRevision(currentRevision, shadowNode);
if (shadowNodeInCurrentRevision == nullptr) {
return std::nullopt;
return DOMRect{};
}
auto layoutMetrics = getRelativeLayoutMetrics(
@@ -548,24 +524,19 @@ measureInWindow(
{.includeTransform = true, .includeViewportOffset = true});
if (layoutMetrics == EmptyLayoutMetrics) {
return std::nullopt;
return DOMRect{};
}
auto frame = layoutMetrics.frame;
return std::tuple{
(double)frame.origin.x,
(double)frame.origin.y,
(double)frame.size.width,
(double)frame.size.height,
return DOMRect{
.x = frame.origin.x,
.y = frame.origin.y,
.width = frame.size.width,
.height = frame.size.height,
};
}
std::optional<std::tuple<
/* x: */ double,
/* y: */ double,
/* width: */ double,
/* height: */ double>>
measureLayout(
std::optional<DOMRect> measureLayout(
const RootShadowNode::Shared& currentRevision,
const ShadowNode& shadowNode,
const ShadowNode& relativeToShadowNode) {
@@ -592,11 +563,11 @@ measureLayout(
auto frame = layoutMetrics.frame;
return std::tuple{
(double)frame.origin.x,
(double)frame.origin.y,
(double)frame.size.width,
(double)frame.size.height,
return DOMRect{
.x = frame.origin.x,
.y = frame.origin.y,
.width = frame.size.width,
.height = frame.size.height,
};
}
@@ -10,18 +10,56 @@
#include <react/renderer/components/root/RootShadowNode.h>
#include <react/renderer/core/ShadowNode.h>
#include <cstdint>
#include <optional>
#include <string>
#include <tuple>
#include <vector>
namespace facebook::react::dom {
struct DOMRect {
double x = 0;
double y = 0;
double width = 0;
double height = 0;
};
struct RNMeasureRect {
double x = 0;
double y = 0;
double width = 0;
double height = 0;
double pageX = 0;
double pageY = 0;
};
struct DOMOffset {
ShadowNode::Shared offsetParent = nullptr;
double top = 0;
double left = 0;
};
struct DOMPoint {
double x = 0;
double y = 0;
};
struct DOMSizeRounded {
int width = 0;
int height = 0;
};
struct DOMBorderWidthRounded {
int top = 0;
int right = 0;
int bottom = 0;
int left = 0;
};
ShadowNode::Shared getParentNode(
const RootShadowNode::Shared& currentRevision,
const ShadowNode& shadowNode);
std::optional<std::vector<ShadowNode::Shared>> getChildNodes(
std::vector<ShadowNode::Shared> getChildNodes(
const RootShadowNode::Shared& currentRevision,
const ShadowNode& shadowNode);
@@ -38,47 +76,28 @@ std::string getTextContent(
const RootShadowNode::Shared& currentRevision,
const ShadowNode& shadowNode);
std::optional<std::tuple<
/* x: */ double,
/* y: */ double,
/* width: */ double,
/* height: */
double>>
getBoundingClientRect(
DOMRect getBoundingClientRect(
const RootShadowNode::Shared& currentRevision,
const ShadowNode& shadowNode,
bool includeTransform);
std::optional<std::tuple<
/* offsetParent: */ ShadowNode::Shared,
/* top: */ double,
/* left: */
double>>
getOffset(
DOMOffset getOffset(
const RootShadowNode::Shared& currentRevision,
const ShadowNode& shadowNode);
std::optional<std::tuple</* scrollLeft: */ double, /* scrollTop: */ double>>
getScrollPosition(
DOMPoint getScrollPosition(
const RootShadowNode::Shared& currentRevision,
const ShadowNode& shadowNode);
std::optional<std::tuple</* scrollWidth: */ int, /* scrollHeight */ int>>
getScrollSize(
DOMSizeRounded getScrollSize(
const RootShadowNode::Shared& currentRevision,
const ShadowNode& shadowNode);
std::optional<std::tuple</* width: */ int, /* height: */ int>> getInnerSize(
DOMSizeRounded getInnerSize(
const RootShadowNode::Shared& currentRevision,
const ShadowNode& shadowNode);
std::optional<std::tuple<
/* topWidth: */ int,
/* rightWidth: */ int,
/* bottomWidth: */ int,
/* leftWidth: */
int>>
getBorderSize(
DOMBorderWidthRounded getBorderWidth(
const RootShadowNode::Shared& currentRevision,
const ShadowNode& shadowNode);
@@ -86,32 +105,17 @@ std::string getTagName(const ShadowNode& shadowNode);
// Non-standard methods from React Native
std::optional<std::tuple<
/* x: */ double,
/* y: */ double,
/* width: */ double,
/* height: */ double,
/* pageX: */ double,
/* pageY: */ double>>
measure(
RNMeasureRect measure(
const RootShadowNode::Shared& currentRevision,
const ShadowNode& shadowNode);
std::optional<std::tuple<
/* x: */ double,
/* y: */ double,
/* width: */ double,
/* height: */ double>>
measureInWindow(
DOMRect measureInWindow(
const RootShadowNode::Shared& currentRevision,
const ShadowNode& shadowNode);
std::optional<std::tuple<
/* x: */ double,
/* y: */ double,
/* width: */ double,
/* height: */ double>>
measureLayout(
// This method returns an optional to signal to go through the error callback
// instead of going through the success callback with an empty DOMRect.
std::optional<DOMRect> measureLayout(
const RootShadowNode::Shared& currentRevision,
const ShadowNode& shadowNode,
const ShadowNode& relativeToShadowNode);
@@ -670,22 +670,22 @@ jsi::Value UIManagerBinding::get(
return jsi::Value::undefined();
}
auto result = dom::measureLayout(
auto maybeRect = dom::measureLayout(
currentRevision, *shadowNode, *relativeToShadowNode);
if (!result) {
if (!maybeRect) {
onFailFunction.call(runtime);
return jsi::Value::undefined();
}
auto [x, y, width, height] = result.value();
auto rect = maybeRect.value();
onSuccessFunction.call(
runtime,
{jsi::Value{runtime, x},
jsi::Value{runtime, y},
jsi::Value{runtime, width},
jsi::Value{runtime, height}});
{jsi::Value{runtime, rect.x},
jsi::Value{runtime, rect.y},
jsi::Value{runtime, rect.width},
jsi::Value{runtime, rect.height}});
return jsi::Value::undefined();
});
}
@@ -715,23 +715,16 @@ jsi::Value UIManagerBinding::get(
return jsi::Value::undefined();
}
auto result = dom::measure(currentRevision, *shadowNode);
if (!result) {
callbackFunction.call(runtime, {0, 0, 0, 0, 0, 0});
return jsi::Value::undefined();
}
auto [x, y, width, height, pageX, pageY] = result.value();
auto measureRect = dom::measure(currentRevision, *shadowNode);
callbackFunction.call(
runtime,
{jsi::Value{runtime, x},
jsi::Value{runtime, y},
jsi::Value{runtime, width},
jsi::Value{runtime, height},
jsi::Value{runtime, pageX},
jsi::Value{runtime, pageY}});
{jsi::Value{runtime, measureRect.x},
jsi::Value{runtime, measureRect.y},
jsi::Value{runtime, measureRect.width},
jsi::Value{runtime, measureRect.height},
jsi::Value{runtime, measureRect.pageX},
jsi::Value{runtime, measureRect.pageY}});
return jsi::Value::undefined();
});
}
@@ -758,24 +751,17 @@ jsi::Value UIManagerBinding::get(
shadowNode->getSurfaceId());
if (currentRevision == nullptr) {
callbackFunction.call(runtime, {0, 0, 0, 0, 0, 0});
callbackFunction.call(runtime, {0, 0, 0, 0});
return jsi::Value::undefined();
}
auto result = dom::measureInWindow(currentRevision, *shadowNode);
if (!result) {
callbackFunction.call(runtime, {0, 0, 0, 0, 0, 0});
return jsi::Value::undefined();
}
auto [x, y, width, height] = result.value();
auto rect = dom::measureInWindow(currentRevision, *shadowNode);
callbackFunction.call(
runtime,
{jsi::Value{runtime, x},
jsi::Value{runtime, y},
jsi::Value{runtime, width},
jsi::Value{runtime, height}});
{jsi::Value{runtime, rect.x},
jsi::Value{runtime, rect.y},
jsi::Value{runtime, rect.width},
jsi::Value{runtime, rect.height}});
return jsi::Value::undefined();
});
}
@@ -897,21 +883,15 @@ jsi::Value UIManagerBinding::get(
return jsi::Value::undefined();
}
auto result = dom::getBoundingClientRect(
auto domRect = dom::getBoundingClientRect(
currentRevision, *shadowNode, includeTransform);
if (!result) {
return jsi::Value::undefined();
}
auto [x, y, width, height] = result.value();
return jsi::Array::createWithElements(
runtime,
jsi::Value{runtime, x},
jsi::Value{runtime, y},
jsi::Value{runtime, width},
jsi::Value{runtime, height});
jsi::Value{runtime, domRect.x},
jsi::Value{runtime, domRect.y},
jsi::Value{runtime, domRect.width},
jsi::Value{runtime, domRect.height});
});
}
@@ -69,9 +69,7 @@ export default class ReactNativeElement
if (node != null) {
const offset = NativeDOM.getOffset(node);
if (offset != null) {
return Math.round(offset[2]);
}
return Math.round(offset[2]);
}
return 0;
@@ -85,7 +83,7 @@ export default class ReactNativeElement
// For children of the root node we currently return offset data
// but a `null` parent because the root node is not accessible
// in JavaScript yet.
if (offset != null && offset[0] != null) {
if (offset[0] != null) {
const offsetParentInstanceHandle = offset[0];
const offsetParent = getPublicInstanceFromInternalInstanceHandle(
offsetParentInstanceHandle,
@@ -104,9 +102,7 @@ export default class ReactNativeElement
if (node != null) {
const offset = NativeDOM.getOffset(node);
if (offset != null) {
return Math.round(offset[1]);
}
return Math.round(offset[1]);
}
return 0;
@@ -36,9 +36,7 @@ export default class ReadOnlyElement extends ReadOnlyNode {
if (node != null) {
const innerSize = NativeDOM.getInnerSize(node);
if (innerSize != null) {
return innerSize[1];
}
return innerSize[1];
}
return 0;
@@ -48,10 +46,8 @@ export default class ReadOnlyElement extends ReadOnlyNode {
const node = getShadowNode(this);
if (node != null) {
const borderSize = NativeDOM.getBorderSize(node);
if (borderSize != null) {
return borderSize[3];
}
const borderSize = NativeDOM.getBorderWidth(node);
return borderSize[3];
}
return 0;
@@ -61,10 +57,8 @@ export default class ReadOnlyElement extends ReadOnlyNode {
const node = getShadowNode(this);
if (node != null) {
const borderSize = NativeDOM.getBorderSize(node);
if (borderSize != null) {
return borderSize[0];
}
const borderSize = NativeDOM.getBorderWidth(node);
return borderSize[0];
}
return 0;
@@ -75,9 +69,7 @@ export default class ReadOnlyElement extends ReadOnlyNode {
if (node != null) {
const innerSize = NativeDOM.getInnerSize(node);
if (innerSize != null) {
return innerSize[0];
}
return innerSize[0];
}
return 0;
@@ -138,9 +130,7 @@ export default class ReadOnlyElement extends ReadOnlyNode {
if (node != null) {
const scrollSize = NativeDOM.getScrollSize(node);
if (scrollSize != null) {
return scrollSize[1];
}
return scrollSize[1];
}
return 0;
@@ -151,9 +141,7 @@ export default class ReadOnlyElement extends ReadOnlyNode {
if (node != null) {
const scrollPosition = NativeDOM.getScrollPosition(node);
if (scrollPosition != null) {
return scrollPosition[0];
}
return scrollPosition[0];
}
return 0;
@@ -164,9 +152,7 @@ export default class ReadOnlyElement extends ReadOnlyNode {
if (node != null) {
const scrollPosition = NativeDOM.getScrollPosition(node);
if (scrollPosition != null) {
return scrollPosition[1];
}
return scrollPosition[1];
}
return 0;
@@ -177,9 +163,7 @@ export default class ReadOnlyElement extends ReadOnlyNode {
if (node != null) {
const scrollSize = NativeDOM.getScrollSize(node);
if (scrollSize != null) {
return scrollSize[0];
}
return scrollSize[0];
}
return 0;
@@ -255,10 +239,7 @@ export function getBoundingClientRect(
if (shadowNode != null) {
const rect = NativeDOM.getBoundingClientRect(shadowNode, includeTransform);
if (rect) {
return new DOMRect(rect[0], rect[1], rect[2], rect[3]);
}
return new DOMRect(rect[0], rect[1], rect[2], rect[3]);
}
// Empty rect if any of the above failed
@@ -318,13 +318,6 @@ export function getChildNodes(
}
const childNodeInstanceHandles = NativeDOM.getChildNodes(shadowNode);
if (
childNodeInstanceHandles == null ||
childNodeInstanceHandles.length === 0
) {
return [];
}
return childNodeInstanceHandles
.map(instanceHandle =>
getPublicInstanceFromInternalInstanceHandle(instanceHandle),
@@ -20,11 +20,11 @@ import nullthrows from 'nullthrows';
export interface Spec extends TurboModule {
+getParentNode: (
shadowNode: mixed /* ShadowNode */,
) => ?mixed /* ?InstanceHandle */;
) => mixed /* ?InstanceHandle */;
+getChildNodes: (
shadowNode: mixed /* ShadowNode */,
) => ?$ReadOnlyArray<mixed> /* ?$ReadOnlyArray<InstanceHandle> */;
) => $ReadOnlyArray<mixed> /* $ReadOnlyArray<InstanceHandle> */;
+isConnected: (shadowNode: mixed /* ShadowNode */) => boolean;
@@ -38,27 +38,27 @@ export interface Spec extends TurboModule {
+getBoundingClientRect: (
shadowNode: mixed /* ShadowNode */,
includeTransform: boolean,
) => ?$ReadOnlyArray<number> /* ?[x: number, y: number, width: number, height: number] */;
) => $ReadOnlyArray<number> /* [x: number, y: number, width: number, height: number] */;
+getOffset: (
shadowNode: mixed /* ShadowNode */,
) => ?$ReadOnlyArray<mixed> /* ?[offsetParent: InstanceHandle, top: number, left: number] */;
) => $ReadOnlyArray<mixed> /* [offsetParent: ?InstanceHandle, top: number, left: number] */;
+getScrollPosition: (
shadowNode: mixed /* ShadowNode */,
) => ?$ReadOnlyArray<number> /* ?[scrollLeft: number, scrollTop: number] */;
) => $ReadOnlyArray<number> /* [scrollLeft: number, scrollTop: number] */;
+getScrollSize: (
shadowNode: mixed /* ShadowNode */,
) => ?$ReadOnlyArray<number> /* ?[scrollWidth: number, scrollHeight: number] */;
) => $ReadOnlyArray<number> /* [scrollWidth: number, scrollHeight: number] */;
+getInnerSize: (
shadowNode: mixed /* ShadowNode */,
) => ?$ReadOnlyArray<number> /* ?[width: number, height: number] */;
) => $ReadOnlyArray<number> /* [width: number, height: number] */;
+getBorderSize: (
+getBorderWidth: (
shadowNode: mixed /* ShadowNode */,
) => ?$ReadOnlyArray<number> /* ?[topWidth: number, rightWidth: number, bottomWidth: number, leftWidth: number] */;
) => $ReadOnlyArray<number> /* [topWidth: number, rightWidth: number, bottomWidth: number, leftWidth: number] */;
+getTagName: (shadowNode: mixed /* ShadowNode */) => string;
@@ -101,7 +101,7 @@ export interface RefinedSpec {
* of an active shadow tree, it returns an array of instance handles of its
* children. Otherwise, it returns an empty array.
*/
+getChildNodes: (shadowNode: ShadowNode) => ?$ReadOnlyArray<InstanceHandle>;
+getChildNodes: (shadowNode: ShadowNode) => $ReadOnlyArray<InstanceHandle>;
/**
* This is a React Native implementation of `Node.prototype.isConnected`
@@ -153,7 +153,7 @@ export interface RefinedSpec {
+getBoundingClientRect: (
shadowNode: ShadowNode,
includeTransform: boolean,
) => ?$ReadOnly<
) => $ReadOnly<
[
/* x: */ number,
/* y: */ number,
@@ -178,8 +178,12 @@ export interface RefinedSpec {
*/
+getOffset: (
shadowNode: ShadowNode,
) => ?$ReadOnly<
[/* offsetParent: */ InstanceHandle, /* top: */ number, /* left: */ number],
) => $ReadOnly<
[
/* offsetParent: */ ?InstanceHandle,
/* top: */ number,
/* left: */ number,
],
>;
/**
@@ -195,7 +199,7 @@ export interface RefinedSpec {
*/
+getScrollPosition: (
shadowNode: ShadowNode,
) => ?$ReadOnly<[/* scrollLeft: */ number, /* scrollTop: */ number]>;
) => $ReadOnly<[/* scrollLeft: */ number, /* scrollTop: */ number]>;
/**
*
@@ -211,7 +215,7 @@ export interface RefinedSpec {
*/
+getScrollSize: (
shadowNode: ShadowNode,
) => ?$ReadOnly<[/* scrollWidth: */ number, /* scrollHeight: */ number]>;
) => $ReadOnly<[/* scrollWidth: */ number, /* scrollHeight: */ number]>;
/**
* This is a method to access the inner size of a shadow node, to implement
@@ -227,7 +231,7 @@ export interface RefinedSpec {
*/
+getInnerSize: (
shadowNode: ShadowNode,
) => ?$ReadOnly<[/* width: */ number, /* height: */ number]>;
) => $ReadOnly<[/* width: */ number, /* height: */ number]>;
/**
* This is a method to access the border size of a shadow node, to implement
@@ -241,9 +245,9 @@ export interface RefinedSpec {
* it has an inline display, it returns `undefined`. Otherwise, it returns its
* border size.
*/
+getBorderSize: (
+getBorderWidth: (
shadowNode: ShadowNode,
) => ?$ReadOnly<
) => $ReadOnly<
[
/* topWidth: */ number,
/* rightWidth: */ number,
@@ -281,7 +285,7 @@ const NativeDOM: RefinedSpec = {
// $FlowExpectedError[incompatible-cast]
return (nullthrows(RawNativeDOM).getChildNodes(
shadowNode,
): ?$ReadOnlyArray<InstanceHandle>);
): $ReadOnlyArray<InstanceHandle>);
},
isConnected(shadowNode) {
@@ -304,7 +308,7 @@ const NativeDOM: RefinedSpec = {
return (nullthrows(RawNativeDOM).getBoundingClientRect(
shadowNode,
includeTransform,
): ?$ReadOnly<
): $ReadOnly<
[
/* x: */ number,
/* y: */ number,
@@ -316,9 +320,9 @@ const NativeDOM: RefinedSpec = {
getOffset(shadowNode) {
// $FlowExpectedError[incompatible-cast]
return (nullthrows(RawNativeDOM).getOffset(shadowNode): ?$ReadOnly<
return (nullthrows(RawNativeDOM).getOffset(shadowNode): $ReadOnly<
[
/* offsetParent: */ InstanceHandle,
/* offsetParent: */ ?InstanceHandle,
/* top: */ number,
/* left: */ number,
],
@@ -327,28 +331,28 @@ const NativeDOM: RefinedSpec = {
getScrollPosition(shadowNode) {
// $FlowExpectedError[incompatible-cast]
return (nullthrows(RawNativeDOM).getScrollPosition(shadowNode): ?$ReadOnly<
return (nullthrows(RawNativeDOM).getScrollPosition(shadowNode): $ReadOnly<
[/* scrollLeft: */ number, /* scrollTop: */ number],
>);
},
getScrollSize(shadowNode) {
// $FlowExpectedError[incompatible-cast]
return (nullthrows(RawNativeDOM).getScrollSize(shadowNode): ?$ReadOnly<
return (nullthrows(RawNativeDOM).getScrollSize(shadowNode): $ReadOnly<
[/* scrollWidth: */ number, /* scrollHeight: */ number],
>);
},
getInnerSize(shadowNode) {
// $FlowExpectedError[incompatible-cast]
return (nullthrows(RawNativeDOM).getInnerSize(shadowNode): ?$ReadOnly<
return (nullthrows(RawNativeDOM).getInnerSize(shadowNode): $ReadOnly<
[/* width: */ number, /* height: */ number],
>);
},
getBorderSize(shadowNode) {
getBorderWidth(shadowNode) {
// $FlowExpectedError[incompatible-cast]
return (nullthrows(RawNativeDOM).getBorderSize(shadowNode): ?$ReadOnly<
return (nullthrows(RawNativeDOM).getBorderWidth(shadowNode): $ReadOnly<
[
/* topWidth: */ number,
/* rightWidth: */ number,
@@ -46,7 +46,7 @@ const NativeDOMMock: NativeDOM = {
(
node: Node,
includeTransform: boolean,
): ?[
): [
/* x:*/ number,
/* y:*/ number,
/* width:*/ number,
@@ -58,7 +58,7 @@ const NativeDOMMock: NativeDOM = {
const currentProps =
nodeInCurrentTree != null ? fromNode(nodeInCurrentTree).props : null;
if (currentProps == null) {
return null;
return [0, 0, 0, 0];
}
const boundingClientRectForTests: ?{
@@ -71,7 +71,7 @@ const NativeDOMMock: NativeDOM = {
currentProps.__boundingClientRectForTests;
if (boundingClientRectForTests == null) {
return null;
return [0, 0, 0, 0];
}
const {x, y, width, height} = boundingClientRectForTests;
@@ -193,14 +193,14 @@ const NativeDOMMock: NativeDOM = {
getOffset: jest.fn(
(
node: Node,
): ?[
/* offsetParent: */ InternalInstanceHandle,
): [
/* offsetParent: */ ?InternalInstanceHandle,
/* offsetTop: */ number,
/* offsetLeft: */ number,
] => {
const ancestors = getAncestorsInCurrentTree(node);
if (ancestors == null) {
return null;
return [null, 0, 0];
}
const [parent, position] = ancestors[ancestors.length - 1];
@@ -209,7 +209,7 @@ const NativeDOMMock: NativeDOM = {
const currentProps =
nodeInCurrentTree != null ? fromNode(nodeInCurrentTree).props : null;
if (currentProps == null || hasDisplayNone(nodeInCurrentTree)) {
return null;
return [null, 0, 0];
}
const offsetForTests: ?{
@@ -220,7 +220,7 @@ const NativeDOMMock: NativeDOM = {
currentProps.__offsetForTests;
if (offsetForTests == null) {
return null;
return [null, 0, 0];
}
let currentIndex = ancestors.length - 1;
@@ -230,7 +230,7 @@ const NativeDOMMock: NativeDOM = {
if (currentIndex >= 0) {
// The node or one of its ancestors have display: none
return null;
return [null, 0, 0];
}
return [
@@ -242,14 +242,14 @@ const NativeDOMMock: NativeDOM = {
),
getScrollPosition: jest.fn(
(node: Node): ?[/* scrollLeft: */ number, /* scrollTop: */ number] => {
(node: Node): [/* scrollLeft: */ number, /* scrollTop: */ number] => {
ensureHostNode(node);
const nodeInCurrentTree = getNodeInCurrentTree(node);
const currentProps =
nodeInCurrentTree != null ? fromNode(nodeInCurrentTree).props : null;
if (currentProps == null) {
return null;
return [0, 0];
}
const scrollForTests: ?{
@@ -261,7 +261,7 @@ const NativeDOMMock: NativeDOM = {
currentProps.__scrollForTests;
if (scrollForTests == null) {
return null;
return [0, 0];
}
const {scrollLeft, scrollTop} = scrollForTests;
@@ -270,14 +270,14 @@ const NativeDOMMock: NativeDOM = {
),
getScrollSize: jest.fn(
(node: Node): ?[/* scrollLeft: */ number, /* scrollTop: */ number] => {
(node: Node): [/* scrollLeft: */ number, /* scrollTop: */ number] => {
ensureHostNode(node);
const nodeInCurrentTree = getNodeInCurrentTree(node);
const currentProps =
nodeInCurrentTree != null ? fromNode(nodeInCurrentTree).props : null;
if (currentProps == null) {
return null;
return [0, 0];
}
const scrollForTests: ?{
@@ -289,7 +289,7 @@ const NativeDOMMock: NativeDOM = {
currentProps.__scrollForTests;
if (scrollForTests == null) {
return null;
return [0, 0];
}
const {scrollWidth, scrollHeight} = scrollForTests;
@@ -298,14 +298,14 @@ const NativeDOMMock: NativeDOM = {
),
getInnerSize: jest.fn(
(node: Node): ?[/* width: */ number, /* height: */ number] => {
(node: Node): [/* width: */ number, /* height: */ number] => {
ensureHostNode(node);
const nodeInCurrentTree = getNodeInCurrentTree(node);
const currentProps =
nodeInCurrentTree != null ? fromNode(nodeInCurrentTree).props : null;
if (currentProps == null) {
return null;
return [0, 0];
}
const innerSizeForTests: ?{
@@ -317,7 +317,7 @@ const NativeDOMMock: NativeDOM = {
currentProps.__innerSizeForTests;
if (innerSizeForTests == null) {
return null;
return [0, 0];
}
const {width, height} = innerSizeForTests;
@@ -325,10 +325,10 @@ const NativeDOMMock: NativeDOM = {
},
),
getBorderSize: jest.fn(
getBorderWidth: jest.fn(
(
node: Node,
): ?[
): [
/* topWidth: */ number,
/* rightWidth: */ number,
/* bottomWidth: */ number,
@@ -340,7 +340,7 @@ const NativeDOMMock: NativeDOM = {
const currentProps =
nodeInCurrentTree != null ? fromNode(nodeInCurrentTree).props : null;
if (currentProps == null) {
return null;
return [0, 0, 0, 0];
}
const borderSizeForTests: ?{
@@ -354,7 +354,7 @@ const NativeDOMMock: NativeDOM = {
currentProps.__borderSizeForTests;
if (borderSizeForTests == null) {
return null;
return [0, 0, 0, 0];
}
const {