Add legacy layout methods from Fabric to DOM native module (#43659)

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

Changelog: [internal]

This adds an implementation for the legacy layout measurement methods in React Native (`measure`, `measureInWindow` and `measureLayout`) in the DOM native module, so we can clean up the API from the `nativeFabricUIManager` binding.

Reviewed By: javache

Differential Revision: D55368141

fbshipit-source-id: 196d4d29be3b78ffc22fdc136be6e0cf5ab9dd26
This commit is contained in:
Rubén Norte
2024-03-27 13:04:34 -07:00
committed by Facebook GitHub Bot
parent ff392b0156
commit 2af1da42ff
4 changed files with 229 additions and 8 deletions
@@ -21,10 +21,11 @@ std::shared_ptr<facebook::react::TurboModule> NativeDOMModuleProvider(
return std::make_shared<facebook::react::NativeDOM>(std::move(jsInvoker));
}
namespace {
using namespace facebook::react;
namespace facebook::react {
RootShadowNode::Shared getCurrentShadowTreeRevision(
#pragma mark - Private helpers
static RootShadowNode::Shared getCurrentShadowTreeRevision(
facebook::jsi::Runtime& runtime,
SurfaceId surfaceId) {
auto& uiManager =
@@ -33,13 +34,14 @@ RootShadowNode::Shared getCurrentShadowTreeRevision(
return shadowTreeRevisionProvider->getCurrentRevision(surfaceId);
}
facebook::react::PointerEventsProcessor& getPointerEventsProcessorFromRuntime(
facebook::jsi::Runtime& runtime) {
static facebook::react::PointerEventsProcessor&
getPointerEventsProcessorFromRuntime(facebook::jsi::Runtime& runtime) {
return facebook::react::UIManagerBinding::getBinding(runtime)
->getPointerEventsProcessor();
}
std::vector<facebook::jsi::Value> getArrayOfInstanceHandlesFromShadowNodes(
static std::vector<facebook::jsi::Value>
getArrayOfInstanceHandlesFromShadowNodes(
const ShadowNode::ListOfShared& nodes,
facebook::jsi::Runtime& runtime) {
// JSI doesn't support adding elements to an array after creation,
@@ -56,9 +58,8 @@ std::vector<facebook::jsi::Value> getArrayOfInstanceHandlesFromShadowNodes(
return nonNullInstanceHandles;
}
} // namespace
namespace facebook::react {
#pragma mark - NativeDOM
NativeDOM::NativeDOM(std::shared_ptr<CallInvoker> jsInvoker)
: NativeDOMCxxSpec(std::move(jsInvoker)) {}
@@ -244,6 +245,8 @@ std::string NativeDOM::getTagName(
return dom::getTagName(*shadowNode);
}
#pragma mark - Pointer events
bool NativeDOM::hasPointerCapture(
jsi::Runtime& rt,
jsi::Value shadowNodeValue,
@@ -269,4 +272,85 @@ void NativeDOM::releasePointerCapture(
pointerId, shadowNodeFromValue(rt, shadowNodeValue).get());
}
#pragma mark - Legacy RN layout APIs
void NativeDOM::measure(
jsi::Runtime& rt,
jsi::Value shadowNodeValue,
jsi::Function callback) {
auto shadowNode = shadowNodeFromValue(rt, shadowNodeValue);
auto currentRevision =
getCurrentShadowTreeRevision(rt, shadowNode->getSurfaceId());
if (currentRevision == nullptr) {
callback.call(rt, {0, 0, 0, 0, 0, 0});
return;
}
auto measureRect = dom::measure(currentRevision, *shadowNode);
callback.call(
rt,
{jsi::Value{rt, measureRect.x},
jsi::Value{rt, measureRect.y},
jsi::Value{rt, measureRect.width},
jsi::Value{rt, measureRect.height},
jsi::Value{rt, measureRect.pageX},
jsi::Value{rt, measureRect.pageY}});
}
void NativeDOM::measureInWindow(
jsi::Runtime& rt,
jsi::Value shadowNodeValue,
jsi::Function callback) {
auto shadowNode = shadowNodeFromValue(rt, shadowNodeValue);
auto currentRevision =
getCurrentShadowTreeRevision(rt, shadowNode->getSurfaceId());
if (currentRevision == nullptr) {
callback.call(rt, {0, 0, 0, 0});
return;
}
auto rect = dom::measureInWindow(currentRevision, *shadowNode);
callback.call(
rt,
{jsi::Value{rt, rect.x},
jsi::Value{rt, rect.y},
jsi::Value{rt, rect.width},
jsi::Value{rt, rect.height}});
}
void NativeDOM::measureLayout(
jsi::Runtime& rt,
jsi::Value shadowNodeValue,
jsi::Value relativeToShadowNodeValue,
jsi::Function onFail,
jsi::Function onSuccess) {
auto shadowNode = shadowNodeFromValue(rt, shadowNodeValue);
auto relativeToShadowNode =
shadowNodeFromValue(rt, relativeToShadowNodeValue);
auto currentRevision =
getCurrentShadowTreeRevision(rt, shadowNode->getSurfaceId());
if (currentRevision == nullptr) {
onFail.call(rt);
return;
}
auto maybeRect =
dom::measureLayout(currentRevision, *shadowNode, *relativeToShadowNode);
if (!maybeRect) {
onFail.call(rt);
return;
}
auto rect = maybeRect.value();
onSuccess.call(
rt,
{jsi::Value{rt, rect.x},
jsi::Value{rt, rect.y},
jsi::Value{rt, rect.width},
jsi::Value{rt, rect.height}});
}
} // namespace facebook::react
@@ -88,6 +88,23 @@ class NativeDOM : public NativeDOMCxxSpec<NativeDOM> {
jsi::Runtime& rt,
jsi::Value shadowNodeValue,
double pointerId);
// Legacy layout APIs
void
measure(jsi::Runtime& rt, jsi::Value shadowNodeValue, jsi::Function callback);
void measureInWindow(
jsi::Runtime& rt,
jsi::Value shadowNodeValue,
jsi::Function callback);
void measureLayout(
jsi::Runtime& rt,
jsi::Value shadowNodeValue,
jsi::Value relativeToShadowNodeValue,
jsi::Function onFail,
jsi::Function onSuccess);
};
} // namespace facebook::react
@@ -17,6 +17,29 @@ import type {TurboModule} from '../../../../../../Libraries/TurboModule/RCTExpor
import * as TurboModuleRegistry from '../../../../../../Libraries/TurboModule/TurboModuleRegistry';
import nullthrows from 'nullthrows';
export type MeasureInWindowOnSuccessCallback = (
x: number,
y: number,
width: number,
height: number,
) => void;
export type MeasureOnSuccessCallback = (
x: number,
y: number,
width: number,
height: number,
pageX: number,
pageY: number,
) => void;
export type MeasureLayoutOnSuccessCallback = (
left: number,
top: number,
width: number,
height: number,
) => void;
export interface Spec extends TurboModule {
+getParentNode: (
shadowNode: mixed /* ShadowNode */,
@@ -76,6 +99,24 @@ export interface Spec extends TurboModule {
shadowNode: mixed /* ShadowNode */,
pointerId: number,
) => void;
/**
* Legacy layout APIs
*/
+measure: (shadowNode: mixed, callback: MeasureOnSuccessCallback) => void;
+measureInWindow: (
shadowNode: mixed,
callback: MeasureInWindowOnSuccessCallback,
) => void;
+measureLayout: (
shadowNode: mixed,
relativeNode: mixed,
onFail: () => void,
onSuccess: MeasureLayoutOnSuccessCallback,
) => void;
}
const RawNativeDOM = (TurboModuleRegistry.get<Spec>('NativeDOMCxx'): ?Spec);
@@ -271,6 +312,27 @@ export interface RefinedSpec {
+setPointerCapture: (shadowNode: ShadowNode, pointerId: number) => void;
+releasePointerCapture: (shadowNode: ShadowNode, pointerId: number) => void;
/**
* Legacy layout APIs
*/
+measure: (
shadowNode: ShadowNode,
callback: MeasureOnSuccessCallback,
) => void;
+measureInWindow: (
shadowNode: ShadowNode,
callback: MeasureInWindowOnSuccessCallback,
) => void;
+measureLayout: (
shadowNode: ShadowNode,
relativeNode: ShadowNode,
onFail: () => void,
onSuccess: MeasureLayoutOnSuccessCallback,
) => void;
}
const NativeDOM: RefinedSpec = {
@@ -380,6 +442,27 @@ const NativeDOM: RefinedSpec = {
pointerId,
);
},
/**
* Legacy layout APIs
*/
measure(shadowNode, callback) {
return nullthrows(RawNativeDOM).measure(shadowNode, callback);
},
measureInWindow(shadowNode, callback) {
return nullthrows(RawNativeDOM).measureInWindow(shadowNode, callback);
},
measureLayout(shadowNode, relativeNode, onFail, onSuccess) {
return nullthrows(RawNativeDOM).measureLayout(
shadowNode,
relativeNode,
onFail,
onSuccess,
);
},
};
export default NativeDOM;
@@ -13,6 +13,11 @@ import type {
InternalInstanceHandle,
Node,
} from '../../../../../../../Libraries/Renderer/shims/ReactNativeTypes';
import type {
MeasureInWindowOnSuccessCallback,
MeasureLayoutOnSuccessCallback,
MeasureOnSuccessCallback,
} from '../NativeDOM';
import typeof NativeDOM from '../NativeDOM';
import {
@@ -371,6 +376,38 @@ const NativeDOMMock: NativeDOM = {
ensureHostNode(node);
return 'RN:' + fromNode(node).viewName;
}),
/**
* Legacy layout APIs
*/
measure: jest.fn((node: Node, callback: MeasureOnSuccessCallback): void => {
ensureHostNode(node);
callback(10, 10, 100, 100, 0, 0);
}),
measureInWindow: jest.fn(
(node: Node, callback: MeasureInWindowOnSuccessCallback): void => {
ensureHostNode(node);
callback(10, 10, 100, 100);
},
),
measureLayout: jest.fn(
(
node: Node,
relativeNode: Node,
onFail: () => void,
onSuccess: MeasureLayoutOnSuccessCallback,
): void => {
ensureHostNode(node);
ensureHostNode(relativeNode);
onSuccess(1, 1, 100, 100);
},
),
};
export default NativeDOMMock;