From 22ac6bcd4ad17ce50903f2055555ee296c1deb88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Mon, 20 Oct 2025 14:38:37 +0200 Subject: [PATCH 01/13] fix(android): fix pressability issues, introduce measureAsyncOnUI to nativeDOM --- .../Libraries/Pressability/Pressability.js | 2 +- .../react/fabric/FabricUIManager.java | 40 +++++++++++++ .../react/fabric/mounting/MeasureAsyncUtil.kt | 56 +++++++++++++++++++ .../react/fabric/mounting/MountingManager.kt | 27 +++++++++ .../react/fabric/FabricMountingManager.cpp | 13 +++++ .../jni/react/fabric/FabricMountingManager.h | 4 ++ .../react/fabric/FabricUIManagerBinding.cpp | 11 ++++ .../jni/react/fabric/FabricUIManagerBinding.h | 4 ++ .../react/nativemodule/dom/NativeDOM.cpp | 24 ++++++++ .../react/nativemodule/dom/NativeDOM.h | 8 +++ .../react/renderer/scheduler/Scheduler.cpp | 9 +++ .../react/renderer/scheduler/Scheduler.h | 3 + .../renderer/scheduler/SchedulerDelegate.h | 4 ++ .../renderer/uimanager/UIManagerDelegate.h | 8 +++ .../webapis/dom/nodes/ReactNativeElement.js | 12 ++++ .../webapis/dom/nodes/specs/NativeDOM.js | 10 ++++ 16 files changed, 234 insertions(+), 1 deletion(-) create mode 100644 packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MeasureAsyncUtil.kt diff --git a/packages/react-native/Libraries/Pressability/Pressability.js b/packages/react-native/Libraries/Pressability/Pressability.js index 0be465bec546..6a4ae91fe9f2 100644 --- a/packages/react-native/Libraries/Pressability/Pressability.js +++ b/packages/react-native/Libraries/Pressability/Pressability.js @@ -805,7 +805,7 @@ export default class Pressability { if (typeof this._responderID === 'number') { UIManager.measure(this._responderID, this._measureCallback); } else { - this._responderID.measure(this._measureCallback); + this._responderID.measureAsyncOnUI(this._measureCallback); } } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java index ee64131ab187..d0fd349edd12 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -25,6 +25,7 @@ import android.view.View; import android.view.accessibility.AccessibilityEvent; import androidx.annotation.AnyThread; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.UiThread; import androidx.core.view.ViewCompat.FocusDirection; @@ -33,6 +34,7 @@ import com.facebook.infer.annotation.Nullsafe; import com.facebook.infer.annotation.ThreadConfined; import com.facebook.proguard.annotations.DoNotStripAny; +import com.facebook.react.bridge.Callback; import com.facebook.react.bridge.ColorPropConverter; import com.facebook.react.bridge.GuardedRunnable; import com.facebook.react.bridge.LifecycleEventListener; @@ -1398,6 +1400,44 @@ public String toString() { }); } + public void measureAsyncOnUI(int surfaceId, int reactTag, final Callback callback) { + mMountItemDispatcher.addMountItem( + new MountItem() { + @Override + public void execute(@NonNull MountingManager mountingManager) { + int[] mMeasureBuffer = new int[4]; + boolean result = mountingManager.measureAsyncOnUI( + surfaceId, + reactTag, + mMeasureBuffer + ); + + if (!result) { + // TODO: add error handling callback + return; + } + + double x = PixelUtil.toDIPFromPixel(mMeasureBuffer[0]); + double y = PixelUtil.toDIPFromPixel(mMeasureBuffer[1]); + double width = PixelUtil.toDIPFromPixel(mMeasureBuffer[2]); + double height = PixelUtil.toDIPFromPixel(mMeasureBuffer[3]); + + callback.invoke(0, 0, width, height, x, y); + } + + @Override + public int getSurfaceId() { + return surfaceId; + } + + @NonNull + @Override + public String toString() { + return "MEASURE_VIEW"; + } + }); + } + @Override public void profileNextBatch() { // TODO T31905686: Remove this method and add support for multi-threading performance counters diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MeasureAsyncUtil.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MeasureAsyncUtil.kt new file mode 100644 index 000000000000..b891debad4ae --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MeasureAsyncUtil.kt @@ -0,0 +1,56 @@ +package com.facebook.react.fabric.mounting + +import android.graphics.RectF +import android.view.View +import android.view.ViewParent + +public object MeasureAsyncUtil { + private val mBoundingBox = RectF() + + /** + * Output buffer will be {x, y, width, height}. + */ + public fun measure(rootView: View, viewToMeasure: View, outputBuffer: IntArray) { + computeBoundingBox(rootView, outputBuffer) + val rootX = outputBuffer[0] + val rootY = outputBuffer[1] + computeBoundingBox(viewToMeasure, outputBuffer) + outputBuffer[0] -= rootX + outputBuffer[1] -= rootY + } + + private fun computeBoundingBox(view: View, outputBuffer: IntArray) { + mBoundingBox.set(0f, 0f, view.width.toFloat(), view.height.toFloat()) + mapRectFromViewToWindowCoords(view, mBoundingBox) + + outputBuffer[0] = Math.round(mBoundingBox.left) + outputBuffer[1] = Math.round(mBoundingBox.top) + outputBuffer[2] = Math.round(mBoundingBox.right - mBoundingBox.left) + outputBuffer[3] = Math.round(mBoundingBox.bottom - mBoundingBox.top) + } + + private fun mapRectFromViewToWindowCoords(view: View, rect: RectF) { + var matrix = view.getMatrix() + if (!matrix.isIdentity) { + matrix.mapRect(rect) + } + + rect.offset(view.left.toFloat(), view.top.toFloat()) + + var parent: ViewParent? = view.parent + while (parent is View) { + val parentView = parent as View + + rect.offset(-parentView.scrollX.toFloat(), -parentView.scrollY.toFloat()) + + matrix = parentView.getMatrix() + if (!matrix.isIdentity) { + matrix.mapRect(rect) + } + + rect.offset(parentView.left.toFloat(), parentView.top.toFloat()) + + parent = parentView.parent + } + } +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.kt index 48410a98298a..36837f81670b 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.kt @@ -22,6 +22,7 @@ import com.facebook.react.bridge.WritableMap import com.facebook.react.fabric.events.EventEmitterWrapper import com.facebook.react.fabric.mounting.mountitems.MountItem import com.facebook.react.touch.JSResponderHandler +import com.facebook.react.uimanager.IllegalViewOperationException import com.facebook.react.uimanager.RootViewManager import com.facebook.react.uimanager.ThemedReactContext import com.facebook.react.uimanager.ViewManagerRegistry @@ -327,6 +328,32 @@ internal class MountingManager( attachmentsPositions, ) + @UiThread + @ThreadConfined(ThreadConfined.UI) + fun measureAsyncOnUI( + surfaceId: Int, + reactTag: Int, + outputBuffer: IntArray, + ): Boolean { + val smm = getSurfaceManagerEnforced(surfaceId, "measure") + val view = try { + smm.getView(reactTag); + } catch (ex: IllegalViewOperationException) { + FLog.e(TAG, "Failed to find view for tag: %d. Error: %s", reactTag, ex.message); + return false + } + + val rootView = try { + smm.getView(surfaceId) + } catch (ex: IllegalViewOperationException) { + FLog.e(TAG, "Failed to find root view for surfaceId: %d. Error: %s", surfaceId, ex.message); + return false + } + + MeasureAsyncUtil.measure(rootView, view, outputBuffer) + return true; + } + fun dispatchEvent( surfaceId: Int, reactTag: Int, diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.cpp index b82bdab278c2..66436ac6ca0a 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -1260,4 +1261,16 @@ void FabricMountingManager::scheduleReactRevisionMerge(SurfaceId surfaceId) { scheduleReactRevisionMerge(javaUIManager_, surfaceId); } +void FabricMountingManager::measureAsyncOnUI( + const ShadowView& shadowView, + const std::function& callback) { + static auto measureJNI = + JFabricUIManager::javaClassStatic()->getMethod)>( + "measureAsyncOnUI"); + + auto javaCallback = JCxxCallbackImpl::newObjectCxxArgs(callback); + + measureJNI(javaUIManager_, shadowView.surfaceId, shadowView.tag, javaCallback); +} + } // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.h b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.h index 377880b658bb..f1643c1ff271 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.h @@ -76,6 +76,10 @@ class FabricMountingManager final { void scheduleReactRevisionMerge(SurfaceId surfaceId); + void measureAsyncOnUI( + const ShadowView& shadowView, + const std::function& callback); + private: bool isOnMainThread(); diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.cpp index dfaac96caefc..fad13d1980b0 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.cpp @@ -820,6 +820,17 @@ void FabricUIManagerBinding::schedulerDidClearPendingSnapshots() { } } +void FabricUIManagerBinding::schedulerMeasureAsyncOnUI( + const facebook::react::ShadowView& shadowView, + const std::function& callback) { + auto mountingManager = getMountingManager("schedulerMeasureAsyncOnUI"); + if (!mountingManager) { + return; + } + + mountingManager->measureAsyncOnUI(shadowView, callback); +} + void FabricUIManagerBinding::onAnimationStarted() { auto mountingManager = getMountingManager("onAnimationStarted"); if (!mountingManager) { diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.h b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.h index caf652d2352e..1f2d3d0d7751 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.h @@ -123,6 +123,10 @@ class FabricUIManagerBinding : public jni::HybridClass, void schedulerDidClearPendingSnapshots() override; + void schedulerMeasureAsyncOnUI( + const ShadowView& shadowView, + const std::function& callback) override; + void setPixelDensity(float pointScaleFactor); void driveCxxAnimations(); diff --git a/packages/react-native/ReactCommon/react/nativemodule/dom/NativeDOM.cpp b/packages/react-native/ReactCommon/react/nativemodule/dom/NativeDOM.cpp index da40ea3b7899..ef7a336b125c 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/dom/NativeDOM.cpp +++ b/packages/react-native/ReactCommon/react/nativemodule/dom/NativeDOM.cpp @@ -466,6 +466,30 @@ void NativeDOM::measureLayout( onSuccess(rect.x, rect.y, rect.width, rect.height); } +void NativeDOM::measureAsyncOnUI( + jsi::Runtime& rt, + std::shared_ptr shadowNode, + const MeasureAsyncOnUICallback& callback) { + UIManager& uiManager = getUIManagerFromRuntime(rt); + UIManagerDelegate* uiManagerDelegate = uiManager.getDelegate(); + if (uiManagerDelegate == nullptr) { + return; + } + + std::function jsCallback = [callback](const folly::dynamic& args) { + // TODO: can we make the rest accept an AsyncFunction directly? + callback.call( + args.at(0).getDouble(), + args.at(1).getDouble(), + args.at(2).getDouble(), + args.at(3).getDouble(), + args.at(4).getDouble(), + args.at(5).getDouble()); + }; + + uiManagerDelegate->uiManagerMeasureAsyncOnUI(shadowNode, jsCallback); +} + #pragma mark - Legacy direct manipulation APIs (for `ReactNativeElement`). void NativeDOM::setNativeProps( diff --git a/packages/react-native/ReactCommon/react/nativemodule/dom/NativeDOM.h b/packages/react-native/ReactCommon/react/nativemodule/dom/NativeDOM.h index 19157a9cd9da..4997db892811 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/dom/NativeDOM.h +++ b/packages/react-native/ReactCommon/react/nativemodule/dom/NativeDOM.h @@ -27,6 +27,9 @@ using MeasureInWindowOnSuccessCallback = SyncCallback; +using MeasureAsyncOnUICallback = + AsyncCallback; + class NativeDOM : public NativeDOMCxxSpec { public: NativeDOM(std::shared_ptr jsInvoker); @@ -108,6 +111,11 @@ class NativeDOM : public NativeDOMCxxSpec { jsi::Function onFail, const MeasureLayoutOnSuccessCallback &onSuccess); + void measureAsyncOnUI( + jsi::Runtime& rt, + std::shared_ptr shadowNode, + const MeasureAsyncOnUICallback& callback); + #pragma mark - Legacy direct manipulation APIs (for `ReactNativeElement`). void setNativeProps(jsi::Runtime &rt, std::shared_ptr shadowNode, jsi::Value updatePayload); diff --git a/packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.cpp b/packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.cpp index 7ea5fc3c782f..86fa4071d27c 100644 --- a/packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.cpp +++ b/packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.cpp @@ -462,6 +462,15 @@ void Scheduler::uiManagerDidStartSurface(const ShadowTree& shadowTree) { } } +void Scheduler::uiManagerMeasureAsyncOnUI( + const std::shared_ptr& shadowNode, + const std::function& callback) { + if (delegate_ != nullptr) { + auto shadowView = ShadowView(*shadowNode); + delegate_->schedulerMeasureAsyncOnUI(shadowView, callback); + } +} + void Scheduler::reportMount(SurfaceId surfaceId) const { uiManager_->reportMount(surfaceId); } diff --git a/packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.h b/packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.h index bd6de832e04d..7c7ff1652d64 100644 --- a/packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.h +++ b/packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.h @@ -103,6 +103,9 @@ class Scheduler final : public UIManagerDelegate { void uiManagerDidFinishReactCommit(const ShadowTree &shadowTree) override; void uiManagerDidPromoteReactRevision(const ShadowTree &shadowTree) override; void uiManagerDidStartSurface(const ShadowTree &shadowTree) override; + void uiManagerMeasureAsyncOnUI( + const std::shared_ptr &shadowNode, + const std::function &callback) override; #pragma mark - ContextContainer std::shared_ptr getContextContainer() const; diff --git a/packages/react-native/ReactCommon/react/renderer/scheduler/SchedulerDelegate.h b/packages/react-native/ReactCommon/react/renderer/scheduler/SchedulerDelegate.h index 06d9773e4ba5..80cb0c4e6c33 100644 --- a/packages/react-native/ReactCommon/react/renderer/scheduler/SchedulerDelegate.h +++ b/packages/react-native/ReactCommon/react/renderer/scheduler/SchedulerDelegate.h @@ -71,6 +71,10 @@ class SchedulerDelegate { virtual void schedulerDidSetViewSnapshot(Tag sourceTag, Tag targetTag, SurfaceId surfaceId) = 0; virtual void schedulerDidClearPendingSnapshots() = 0; + virtual void schedulerMeasureAsyncOnUI( + const ShadowView& shadowView, + const std::function& callback) = 0; + virtual ~SchedulerDelegate() noexcept = default; }; diff --git a/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerDelegate.h b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerDelegate.h index 235b1fe34eac..b6aa0cf43356 100644 --- a/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerDelegate.h +++ b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerDelegate.h @@ -79,6 +79,14 @@ class UIManagerDelegate { */ virtual void uiManagerShouldRemoveEventListener(const std::shared_ptr &listener) = 0; + /* + * Measures the layout of the shadow node async on the UI thread using the native layout hierarchy. + * As this has to schedule a call on the UI thread its async. + */ + virtual void uiManagerMeasureAsyncOnUI( + const std::shared_ptr& shadowNode, + const std::function& callback) = 0; + /* * Start surface. */ diff --git a/packages/react-native/src/private/webapis/dom/nodes/ReactNativeElement.js b/packages/react-native/src/private/webapis/dom/nodes/ReactNativeElement.js index 9fef664f4004..a7d35e73deae 100644 --- a/packages/react-native/src/private/webapis/dom/nodes/ReactNativeElement.js +++ b/packages/react-native/src/private/webapis/dom/nodes/ReactNativeElement.js @@ -196,6 +196,18 @@ class ReactNativeElement extends ReadOnlyElement { } } + /** + * Same as `measure()`, but instead of using the shadow nodes layout + * information, it uses the native layout hierarchy to measure the view on the + * UI thread. + */ + measureAsyncOnUI(callback: MeasureOnSuccessCallback) { + const node = getNativeElementReference(this); + if (node != null) { + NativeDOM.measureAsyncOnUI(node, callback); + } + } + /** * Determines the location of the given view in the window and returns the * values via an async callback. If the React root view is embedded in diff --git a/packages/react-native/src/private/webapis/dom/nodes/specs/NativeDOM.js b/packages/react-native/src/private/webapis/dom/nodes/specs/NativeDOM.js index 12a34399221c..895e89607834 100644 --- a/packages/react-native/src/private/webapis/dom/nodes/specs/NativeDOM.js +++ b/packages/react-native/src/private/webapis/dom/nodes/specs/NativeDOM.js @@ -159,6 +159,11 @@ export interface Spec extends TurboModule { onSuccess: MeasureLayoutOnSuccessCallback, ) => void; + +measureAsyncOnUI: ( + nativeElementReference: mixed, + callback: MeasureInWindowOnSuccessCallback, + ) => void; + /** * Legacy direct manipulation APIs (for `ReactNativeElement`). */ @@ -433,6 +438,11 @@ export interface RefinedSpec { onSuccess: MeasureLayoutOnSuccessCallback, ) => void; + +measureAsyncOnUI: ( + nativeElementReference: NativeElementReference, + callback: MeasureInWindowOnSuccessCallback, + ) => void; + /** * Legacy direct manipulation APIs */ From 070a55788ab049a1a8158dee5d998e428ef87ebe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Mon, 20 Oct 2025 14:41:30 +0200 Subject: [PATCH 02/13] add copyright header --- .../com/facebook/react/fabric/mounting/MeasureAsyncUtil.kt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MeasureAsyncUtil.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MeasureAsyncUtil.kt index b891debad4ae..9680cf5e99e3 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MeasureAsyncUtil.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MeasureAsyncUtil.kt @@ -1,3 +1,10 @@ +/* + * 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. + */ + package com.facebook.react.fabric.mounting import android.graphics.RectF From 96a10abf4b2c6fc0003919defe28caaecd77d0ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Tue, 21 Oct 2025 10:23:37 +0200 Subject: [PATCH 03/13] implement iOS --- .../Fabric/Mounting/RCTMountingManager.h | 3 +++ .../Fabric/Mounting/RCTMountingManager.mm | 26 +++++++++++++++++++ .../react-native/React/Fabric/RCTScheduler.h | 3 +++ .../react-native/React/Fabric/RCTScheduler.mm | 5 ++++ .../React/Fabric/RCTSurfacePresenter.mm | 13 ++++++++++ 5 files changed, 50 insertions(+) diff --git a/packages/react-native/React/Fabric/Mounting/RCTMountingManager.h b/packages/react-native/React/Fabric/Mounting/RCTMountingManager.h index 70a56433d57b..e1f240eec1fa 100644 --- a/packages/react-native/React/Fabric/Mounting/RCTMountingManager.h +++ b/packages/react-native/React/Fabric/Mounting/RCTMountingManager.h @@ -9,6 +9,7 @@ #import #import +#import #import #import #import @@ -69,6 +70,8 @@ NS_ASSUME_NONNULL_BEGIN - (void)synchronouslyUpdateViewOnUIThread:(ReactTag)reactTag changedProps:(folly::dynamic)props componentDescriptor:(const facebook::react::ComponentDescriptor &)componentDescriptor; + +- (void)measureAsyncOnUI:(ReactTag)reactTag rootView:(UIView*)rootView callback:(const std::function &)callback; @end NS_ASSUME_NONNULL_END diff --git a/packages/react-native/React/Fabric/Mounting/RCTMountingManager.mm b/packages/react-native/React/Fabric/Mounting/RCTMountingManager.mm index 68662f06d59b..f3f51578aeaa 100644 --- a/packages/react-native/React/Fabric/Mounting/RCTMountingManager.mm +++ b/packages/react-native/React/Fabric/Mounting/RCTMountingManager.mm @@ -347,4 +347,30 @@ - (void)synchronouslyDispatchAccessbilityEventOnUIThread:(ReactTag)reactTag even } } +- (void)measureAsyncOnUI:(ReactTag)reactTag rootView:(UIView*)rootView callback:(const std::function &)callback { + RCTAssertMainQueue(); + + UIView *view = [self->_componentViewRegistry findComponentViewWithTag:reactTag]; + if (!view) { + // this view was probably collapsed out + RCTLogWarn(@"measure cannot find view with tag #%@", reactTag); + callback({}); + return; + } + + // By convention, all coordinates, whether they be touch coordinates, or + // measurement coordinates are with respect to the root view. + CGRect frame = view.frame; + CGRect globalBounds = [view convertRect:view.bounds toView:rootView]; + + callback( + folly::dynamic::array(frame.origin.x, + frame.origin.y, + globalBounds.size.width, + globalBounds.size.height, + globalBounds.origin.x, + globalBounds.origin.y) + ); +} + @end diff --git a/packages/react-native/React/Fabric/RCTScheduler.h b/packages/react-native/React/Fabric/RCTScheduler.h index 8b809580c10c..2d925e70a712 100644 --- a/packages/react-native/React/Fabric/RCTScheduler.h +++ b/packages/react-native/React/Fabric/RCTScheduler.h @@ -45,6 +45,9 @@ NS_ASSUME_NONNULL_BEGIN forShadowView:(const facebook::react::ShadowView &)shadowView; - (void)schedulerDidSynchronouslyUpdateViewOnUIThread:(facebook::react::Tag)reactTag props:(folly::dynamic)props; + +- (void)schedulerMeasureAsyncOnUI:(const facebook::react::ShadowView &)shadowView + callback:(const std::function &)callback; @end /** diff --git a/packages/react-native/React/Fabric/RCTScheduler.mm b/packages/react-native/React/Fabric/RCTScheduler.mm index 9519f18428e4..46e723ad2444 100644 --- a/packages/react-native/React/Fabric/RCTScheduler.mm +++ b/packages/react-native/React/Fabric/RCTScheduler.mm @@ -85,6 +85,11 @@ void schedulerDidUpdateShadowTree(const std::unordered_map // This delegate method is not currently used on iOS. } + void schedulerMeasureAsyncOnUI(const ShadowView& shadowView, const std::function &callback) override { + RCTScheduler *scheduler = (__bridge RCTScheduler *)scheduler_; + [scheduler.delegate schedulerMeasureAsyncOnUI:shadowView callback:callback]; + } + void schedulerDidCaptureViewSnapshot(Tag tag, SurfaceId surfaceId) override { // Does nothing. diff --git a/packages/react-native/React/Fabric/RCTSurfacePresenter.mm b/packages/react-native/React/Fabric/RCTSurfacePresenter.mm index 0e4bbe376463..3bb47854a1c8 100644 --- a/packages/react-native/React/Fabric/RCTSurfacePresenter.mm +++ b/packages/react-native/React/Fabric/RCTSurfacePresenter.mm @@ -424,6 +424,19 @@ - (void)schedulerDidSetIsJSResponder:(BOOL)isJSResponder [_mountingManager setIsJSResponder:isJSResponder blockNativeResponder:blockNativeResponder forShadowView:shadowView]; } +- (void)schedulerMeasureAsyncOnUI:(const facebook::react::ShadowView &)shadowView callback:(const std::function &)callback { + ReactTag tag = shadowView.tag; + SurfaceId surfaceId = shadowView.surfaceId; + RCTFabricSurface *surface = [self surfaceForRootTag:surfaceId]; + + std::function callbackCopy = callback; + RCTExecuteOnMainQueue(^{ + UIView *rootView = surface.view; + [self->_mountingManager measureAsyncOnUI:tag rootView:rootView callback:callbackCopy]; + }); +} + + - (void)addObserver:(id)observer { std::unique_lock lock(_observerListMutex); From f8f3c0c3acbb6e2b9c824083206919e958b21058 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Tue, 21 Oct 2025 10:33:30 +0200 Subject: [PATCH 04/13] formatting --- .../react-native/React/Fabric/Mounting/RCTMountingManager.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/react-native/React/Fabric/Mounting/RCTMountingManager.h b/packages/react-native/React/Fabric/Mounting/RCTMountingManager.h index e1f240eec1fa..24e8fe989596 100644 --- a/packages/react-native/React/Fabric/Mounting/RCTMountingManager.h +++ b/packages/react-native/React/Fabric/Mounting/RCTMountingManager.h @@ -7,9 +7,9 @@ #import +#import #import #import -#import #import #import #import @@ -71,7 +71,9 @@ NS_ASSUME_NONNULL_BEGIN changedProps:(folly::dynamic)props componentDescriptor:(const facebook::react::ComponentDescriptor &)componentDescriptor; -- (void)measureAsyncOnUI:(ReactTag)reactTag rootView:(UIView*)rootView callback:(const std::function &)callback; +- (void)measureAsyncOnUI:(ReactTag)reactTag + rootView:(UIView *)rootView + callback:(const std::function &)callback; @end NS_ASSUME_NONNULL_END From 5207ac3e63a3cb18027098cb868845a98249bea3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Tue, 21 Oct 2025 10:40:56 +0200 Subject: [PATCH 05/13] yarn run build-types --- packages/react-native/ReactNativeApi.d.ts | 239 +++++++++++----------- 1 file changed, 120 insertions(+), 119 deletions(-) diff --git a/packages/react-native/ReactNativeApi.d.ts b/packages/react-native/ReactNativeApi.d.ts index 567e2db03e99..8b41b607455c 100644 --- a/packages/react-native/ReactNativeApi.d.ts +++ b/packages/react-native/ReactNativeApi.d.ts @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<> + * @generated SignedSource<<3ea562eab1766a44e0823179cbb71967>> * * This file was generated by scripts/js-api/build-types/index.js. */ @@ -3978,6 +3978,7 @@ declare class ReactNativeElement_default extends ReadOnlyElement_default { protected constructor() focus(): void measure(callback: MeasureOnSuccessCallback): void + measureAsyncOnUI(callback: MeasureOnSuccessCallback): void measureInWindow(callback: MeasureInWindowOnSuccessCallback): void measureLayout( relativeToNativeNode: HostInstance | number, @@ -5891,24 +5892,24 @@ declare type WrapperComponentProvider = ( appParameters: Object, ) => React.ComponentType export { - AccessibilityActionEvent, // a0d4daa0 - AccessibilityInfo, // 23a3aa9b + AccessibilityActionEvent, // defc93d8 + AccessibilityInfo, // 13eeb115 AccessibilityProps, // 5a2836fc AccessibilityRole, // f2f2e066 AccessibilityState, // b0c2b3f7 AccessibilityValue, // cf8bcb74 ActionSheetIOS, // b558559e ActionSheetIOSOptions, // 1756eb5a - ActivityIndicator, // 2a0518e9 - ActivityIndicatorInstance, // a82dd4e7 - ActivityIndicatorProps, // f330d1dc + ActivityIndicator, // 65efa5b0 + ActivityIndicatorInstance, // 1cdc511b + ActivityIndicatorProps, // e0e64cc3 Alert, // 5bf12165 AlertButton, // bf1a3b60 AlertButtonStyle, // ec9fb242 AlertOptions, // a0cdac0f AlertType, // 5ab91217 AndroidKeyboardEvent, // e03becc8 - Animated, // 09c0f98d + Animated, // 81d059ad AppConfig, // 35c0ca70 AppRegistry, // 7ef8e53a AppState, // 12012be5 @@ -5918,13 +5919,13 @@ export { AutoCapitalize, // c0e857a0 BackHandler, // f139fc69 BackPressEventName, // 4620fb76 - BlurEvent, // 4ba4f941 + BlurEvent, // a075b76a BoxShadowValue, // b679703f - Button, // d7ffb46e - ButtonInstance, // 3f83f7e7 - ButtonProps, // 35ffc98c + Button, // fa4ca46d + ButtonInstance, // 484067fd + ButtonProps, // ab80bf52 Clipboard, // 41addb89 - CodegenTypes, // ab4986cc + CodegenTypes, // 80bf9569 ColorSchemeName, // 6615edd6 ColorValue, // 98989a8f ComponentProvider, // bf78f91b @@ -5940,10 +5941,10 @@ export { DimensionsPayload, // 653bc26c DisplayMetrics, // 1dc35cef DisplayMetricsAndroid, // 872e62eb - DrawerLayoutAndroid, // 52018924 + DrawerLayoutAndroid, // 4a4e7ca6 DrawerLayoutAndroidInstance, // c0694352 - DrawerLayoutAndroidProps, // 8dfceaf9 - DrawerSlideEvent, // c4ab8fba + DrawerLayoutAndroidProps, // cd03744e + DrawerSlideEvent, // 461b9f01 DropShadowValue, // e9df2606 DynamicColorIOS, // d96c228c DynamicColorIOSTuple, // 023ce58e @@ -5957,31 +5958,31 @@ export { EventSubscription, // b8d084aa ExtendedExceptionData, // 5a6ccf5a FilterFunction, // bf24c0e3 - FlatList, // d98f538f - FlatListInstance, // 62941810 - FlatListProps, // deadf762 - FocusEvent, // 850f1517 + FlatList, // f818f29a + FlatListInstance, // f75e72c1 + FlatListProps, // c86b58a2 + FocusEvent, // 34045e67 FontVariant, // 7c7558bb - GestureResponderEvent, // 14d3e77a - GestureResponderHandlers, // c976c2ea - HostComponent, // a611806a - HostInstance, // f78dcaf8 + GestureResponderEvent, // 12c377eb + GestureResponderHandlers, // 65ce6ad4 + HostComponent, // 533df39e + HostInstance, // 5d598069 I18nManager, // f9870e00 IEventEmitter, // fbef6131 IOSKeyboardEvent, // e67bfe3a IgnorePattern, // ec6f6ece - Image, // c6bb54ac - ImageBackground, // f4c8dcea - ImageBackgroundInstance, // 7c3cd110 - ImageBackgroundProps, // 3b22066a - ImageErrorEvent, // 978933f4 - ImageInstance, // 9a100753 - ImageLoadEvent, // 77f0b718 - ImageProgressEventIOS, // 445331a4 - ImageProps, // 3765f681 + Image, // d23fa8f6 + ImageBackground, // 9c41b448 + ImageBackgroundInstance, // 69d5c552 + ImageBackgroundProps, // b912d1c7 + ImageErrorEvent, // b2e70c81 + ImageInstance, // 66dcace1 + ImageLoadEvent, // 7d04a32c + ImageProgressEventIOS, // 3d6dfbd7 + ImageProps, // 53bf92d4 ImagePropsAndroid, // 9fd9bcbb - ImagePropsBase, // 2cab4147 - ImagePropsIOS, // 4a080668 + ImagePropsBase, // a00dcd00 + ImagePropsIOS, // a4f7a943 ImageRequireSource, // 681d683b ImageResolvedAssetSource, // f3060931 ImageSize, // 1c47cf88 @@ -5993,13 +5994,13 @@ export { InputAccessoryViewProps, // d94dc290 InputModeOptions, // 4e8581b9 Insets, // e7fe432a - KeyDownEvent, // 5b147614 + KeyDownEvent, // d21b5429 KeyEvent, // 20fa4267 - KeyUpEvent, // 57f832c5 + KeyUpEvent, // 9247d64e Keyboard, // 49414c97 - KeyboardAvoidingView, // 0af358b6 - KeyboardAvoidingViewInstance, // 1a3c8471 - KeyboardAvoidingViewProps, // 83473aa1 + KeyboardAvoidingView, // dd3657b9 + KeyboardAvoidingViewInstance, // 0b8a4390 + KeyboardAvoidingViewProps, // 729411f8 KeyboardEvent, // c3f895d4 KeyboardEventEasing, // af4091c8 KeyboardEventName, // 59299ad6 @@ -6012,7 +6013,7 @@ export { LayoutAnimationProperty, // 52995f01 LayoutAnimationType, // 2da0a29b LayoutAnimationTypes, // 081b3bde - LayoutChangeEvent, // 98960b70 + LayoutChangeEvent, // 8857400c LayoutConformanceProps, // 055f03b8 LayoutRectangle, // 6601b294 Linking, // 9a6a174d @@ -6024,32 +6025,32 @@ export { MeasureInWindowOnSuccessCallback, // a285f598 MeasureLayoutOnSuccessCallback, // 3592502a MeasureOnSuccessCallback, // 82824e59 - Modal, // f30cc19f - ModalBaseProps, // 71945951 - ModalInstance, // d466ce77 - ModalProps, // 4eb5a731 + Modal, // fa1e3453 + ModalBaseProps, // f7b0cfd9 + ModalInstance, // 7af0fecd + ModalProps, // 07f1d7d0 ModalPropsAndroid, // 515fb173 - ModalPropsIOS, // 0e13cfcc - ModeChangeEvent, // f64bf69d - MouseEvent, // d1f889fd + ModalPropsIOS, // 922bebe5 + ModeChangeEvent, // 56ede277 + MouseEvent, // d05f83e7 NativeAppEventEmitter, // 08d4c47d NativeColorValue, // d2094c29 - NativeComponentRegistry, // c8fc2fb5 + NativeComponentRegistry, // 88b216dc NativeEventEmitter, // 27f97c1a NativeEventSubscription, // de3942e7 NativeModules, // 4597cd36 - NativeMouseEvent, // 16c856a5 - NativePointerEvent, // 64ff2151 + NativeMouseEvent, // acc5cd57 + NativePointerEvent, // a9ea3670 NativeScrollEvent, // caad7f53 - NativeSyntheticEvent, // 534aaa92 + NativeSyntheticEvent, // 1677698d NativeTouchEvent, // 59b676df NativeUIEvent, // 44ac26ac Networking, // bbc5be42 OpaqueColorValue, // 25f3fa5b - PanResponder, // f8f71cac - PanResponderCallbacks, // 6d63e7be + PanResponder, // f92f601f + PanResponderCallbacks, // f1fc7835 PanResponderGestureState, // 54baf558 - PanResponderInstance, // 69cebbe8 + PanResponderInstance, // c8b3a13a Permission, // 06473f4f PermissionStatus, // 4b7de97b PermissionsAndroid, // db2a401e @@ -6059,32 +6060,32 @@ export { PlatformOSType, // 0a17561e PlatformSelectSpec, // 09ed7758 PointValue, // 69db075f - PointerEvent, // ff599afe - PressabilityConfig, // faab5639 - PressabilityEventHandlers, // 0b910091 - Pressable, // d508cef4 + PointerEvent, // e43d0d94 + PressabilityConfig, // 79dc56a6 + PressabilityEventHandlers, // 5e980f94 + Pressable, // 3ce0935c PressableAndroidRippleConfig, // ee32eaca - PressableInstance, // eebfe911 - PressableProps, // f5bffd11 + PressableInstance, // c71247d7 + PressableProps, // 538da969 PressableStateCallbackType, // 9af36561 ProcessedColorValue, // 33f74304 - ProgressBarAndroid, // 8ef8ba6a - ProgressBarAndroidInstance, // ab545ef1 - ProgressBarAndroidProps, // f31ec709 + ProgressBarAndroid, // fa82f551 + ProgressBarAndroidInstance, // 81fb6d4e + ProgressBarAndroidProps, // cfde2d2e PublicRootInstance, // 8040afd7 - PublicTextInstance, // 6937c7bf + PublicTextInstance, // f663c6a0 PushNotificationEventName, // 84e7e150 PushNotificationIOS, // b4d1fe78 PushNotificationPermissions, // c2e7ae4f Rationale, // 5df1b1c1 ReactNativeVersion, // abd76827 - RefreshControl, // 48160637 - RefreshControlInstance, // f7d632ba - RefreshControlProps, // b028bb5a + RefreshControl, // 229968b5 + RefreshControlInstance, // 8c3eef80 + RefreshControlProps, // 3056f0f4 RefreshControlPropsAndroid, // 99f64c97 RefreshControlPropsIOS, // 72a36381 Registry, // 6c39216d - ResponderSyntheticEvent, // ebfa7f48 + ResponderSyntheticEvent, // 2adfe839 ReturnKeyTypeOptions, // afd47ba3 Role, // af7b889d RootTag, // 3cd10504 @@ -6092,24 +6093,24 @@ export { RootViewStyleProvider, // 8792d506 Runnable, // 594dd93a Runnables, // 4367c557 - SafeAreaView, // 963d85d0 - SafeAreaViewInstance, // 21dba39c + SafeAreaView, // 0a71e2d1 + SafeAreaViewInstance, // 1180ae89 ScaledSize, // 07e417c7 - ScrollEvent, // d7abdd0a - ScrollResponderType, // 8864c38f + ScrollEvent, // 79e18191 + ScrollResponderType, // fcbdfef5 ScrollToLocationParamsType, // d7ecdad1 - ScrollView, // c67a52a8 - ScrollViewImperativeMethods, // b4c3feed - ScrollViewInstance, // 971d4924 - ScrollViewProps, // 3ab71e04 + ScrollView, // caab26f1 + ScrollViewImperativeMethods, // 50f8b469 + ScrollViewInstance, // ef3127f8 + ScrollViewProps, // 74805277 ScrollViewPropsAndroid, // 44210553 - ScrollViewPropsIOS, // b7921e26 + ScrollViewPropsIOS, // 9625219c ScrollViewScrollToOptions, // 3313411e SectionBase, // dca83594 - SectionList, // e4cd2cce + SectionList, // 343e0ee5 SectionListData, // e0d79987 - SectionListInstance, // 06be7c37 - SectionListProps, // 983ca166 + SectionListInstance, // 4cd8666e + SectionListProps, // 14b886ca SectionListRenderItem, // 466e3e87 SectionListRenderItemInfo, // d809238e Separators, // 6a45f7e3 @@ -6128,75 +6129,75 @@ export { StyleProp, // fa0e9b4a StyleSheet, // 29f1b323 SubmitBehavior, // c4ddf490 - Switch, // 370e8ea2 - SwitchChangeEvent, // 899635b1 - SwitchInstance, // 3c50eec5 - SwitchProps, // 61214431 + Switch, // d7800274 + SwitchChangeEvent, // e30a4e7e + SwitchInstance, // 8160b16d + SwitchProps, // f4bb56ec Systrace, // 626d178c TVViewPropsIOS, // 330ce7b5 TargetedEvent, // 16e98910 TaskProvider, // 266dedf2 - Text, // 17a6c136 + Text, // 4acc1069 TextContentType, // 239b3ecc - TextInput, // 8f39debf + TextInput, // 9c6aff77 TextInputAndroidProps, // 3f09ce49 - TextInputChangeEvent, // f55eef98 - TextInputContentSizeChangeEvent, // a27cd32a - TextInputEndEditingEvent, // e690b56b - TextInputFocusEvent, // 19851a88 + TextInputChangeEvent, // c7d2d518 + TextInputContentSizeChangeEvent, // f8e26aaf + TextInputEndEditingEvent, // f19faa1e + TextInputFocusEvent, // f1c9a798 TextInputIOSProps, // 0d05a855 - TextInputInstance, // 5a0c0e0d - TextInputKeyPressEvent, // 546c5d07 - TextInputProps, // 899880a2 - TextInputSelectionChangeEvent, // e58f2abc - TextInputSubmitEditingEvent, // 6bcb2aa5 - TextInstance, // 05463a96 - TextLayoutEvent, // 3f54186f - TextProps, // a7822140 + TextInputInstance, // c3780dfa + TextInputKeyPressEvent, // 2eadfdab + TextInputProps, // 440136f6 + TextInputSelectionChangeEvent, // 7719d5e8 + TextInputSubmitEditingEvent, // 222a4373 + TextInstance, // 4065c355 + TextLayoutEvent, // 1dd1d80f + TextProps, // 3af13ab2 TextStyle, // ab0f32ca ToastAndroid, // 88a8969a - Touchable, // b280637f - TouchableHighlight, // 452aa27b - TouchableHighlightInstance, // b510c0eb - TouchableHighlightProps, // dc0126c9 - TouchableNativeFeedback, // bee68787 - TouchableNativeFeedbackInstance, // f66604fc - TouchableNativeFeedbackProps, // 91de1ed8 - TouchableOpacity, // 0c1239fd - TouchableOpacityInstance, // b186055b - TouchableOpacityProps, // 4c5af3d2 - TouchableWithoutFeedback, // 8d374ae1 - TouchableWithoutFeedbackProps, // 65c8c30a + Touchable, // ff06040e + TouchableHighlight, // e67f137c + TouchableHighlightInstance, // b6a0637b + TouchableHighlightProps, // baae0a39 + TouchableNativeFeedback, // ffa96f33 + TouchableNativeFeedbackInstance, // 1a63ff3d + TouchableNativeFeedbackProps, // 6963e3fa + TouchableOpacity, // 076ab1fb + TouchableOpacityInstance, // 31bffbb6 + TouchableOpacityProps, // 3db27231 + TouchableWithoutFeedback, // df7553a8 + TouchableWithoutFeedbackProps, // 8fc79d4e TransformsStyle, // 65e70f18 TurboModule, // dfe29706 TurboModuleRegistry, // 4ace6db2 UIManager, // a1a7cc01 UTFSequence, // ad625158 Vibration, // 31e4bbf8 - View, // 6b216377 - ViewInstance, // ffde5573 - ViewProps, // cbb6c0b5 - ViewPropsAndroid, // 03c17367 + View, // 0bb2d20d + ViewInstance, // 246d0db4 + ViewProps, // 0cc8a460 + ViewPropsAndroid, // 50b64a0e ViewPropsIOS, // 58ee19bf ViewStyle, // e45056b1 VirtualViewMode, // 6be59722 VirtualizedList, // 68c7345e VirtualizedListInstance, // 423ee7c0 - VirtualizedListProps, // f05a76fd + VirtualizedListProps, // 9f4202fa VirtualizedSectionList, // 9fd9cd61 VirtualizedSectionListInstance, // 12b706d5 - VirtualizedSectionListProps, // 283047f7 + VirtualizedSectionListProps, // d1768c9d WrapperComponentProvider, // 4b8c7962 codegenNativeCommands, // 628a7c0a - codegenNativeComponent, // 32a1bca6 + codegenNativeComponent, // 7c62ddde findNodeHandle, // 93f80214 processColor, // 6e877698 registerCallableModule, // 839c8cfe - requireNativeComponent, // aa36a6dd + requireNativeComponent, // 7ae00be7 useAnimatedColor, // e3511f81 useAnimatedValue, // b18adb63 useAnimatedValueXY, // c7ee2332 useColorScheme, // d585efdb - usePressability, // 095343b5 + usePressability, // 97040468 useWindowDimensions, // bb4b683f } From b152f142bdad827dea10ecc074d8fda7a94284a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Tue, 21 Oct 2025 10:50:53 +0200 Subject: [PATCH 06/13] use correct callback type --- .../src/private/webapis/dom/nodes/specs/NativeDOM.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-native/src/private/webapis/dom/nodes/specs/NativeDOM.js b/packages/react-native/src/private/webapis/dom/nodes/specs/NativeDOM.js index 895e89607834..c3fd78e9c5b1 100644 --- a/packages/react-native/src/private/webapis/dom/nodes/specs/NativeDOM.js +++ b/packages/react-native/src/private/webapis/dom/nodes/specs/NativeDOM.js @@ -440,7 +440,7 @@ export interface RefinedSpec { +measureAsyncOnUI: ( nativeElementReference: NativeElementReference, - callback: MeasureInWindowOnSuccessCallback, + callback: MeasureOnSuccessCallback, ) => void; /** From 7aa9495e366168990d22ff35f1dcb232353786b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Tue, 21 Oct 2025 11:15:10 +0200 Subject: [PATCH 07/13] fix fantom test --- .../react/renderer/scheduler/SchedulerDelegateImpl.cpp | 6 ++++++ .../react/renderer/scheduler/SchedulerDelegateImpl.h | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/packages/react-native/ReactCxxPlatform/react/renderer/scheduler/SchedulerDelegateImpl.cpp b/packages/react-native/ReactCxxPlatform/react/renderer/scheduler/SchedulerDelegateImpl.cpp index 9ad1bb1a4f54..ad627f2da2a6 100644 --- a/packages/react-native/ReactCxxPlatform/react/renderer/scheduler/SchedulerDelegateImpl.cpp +++ b/packages/react-native/ReactCxxPlatform/react/renderer/scheduler/SchedulerDelegateImpl.cpp @@ -87,4 +87,10 @@ void SchedulerDelegateImpl::schedulerDidSetViewSnapshot( void SchedulerDelegateImpl::schedulerDidClearPendingSnapshots() {} +void SchedulerDelegateImpl::schedulerMeasureAsyncOnUI( + const ShadowView& /*shadowView*/, + const std::function& /*callback*/) { + // No-op implementation, can be overridden by subclasses if needed +} + } // namespace facebook::react diff --git a/packages/react-native/ReactCxxPlatform/react/renderer/scheduler/SchedulerDelegateImpl.h b/packages/react-native/ReactCxxPlatform/react/renderer/scheduler/SchedulerDelegateImpl.h index 089b64d5731c..8b7db29d6fcd 100644 --- a/packages/react-native/ReactCxxPlatform/react/renderer/scheduler/SchedulerDelegateImpl.h +++ b/packages/react-native/ReactCxxPlatform/react/renderer/scheduler/SchedulerDelegateImpl.h @@ -57,6 +57,10 @@ class SchedulerDelegateImpl : public SchedulerDelegate { void schedulerDidClearPendingSnapshots() override; + void schedulerMeasureAsyncOnUI( + const ShadowView& shadowView, + const std::function& callback) override; + std::shared_ptr mountingManager_; std::shared_ptr uiManager_; }; From 43be8693651970b70f38e5872a414b202fb284ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Thu, 18 Jun 2026 09:35:03 +0200 Subject: [PATCH 08/13] feat(pressability): gate native hierarchy measurement --- .../Libraries/Pressability/Pressability.js | 6 +++++- .../featureflags/ReactNativeFeatureFlags.config.js | 11 +++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/packages/react-native/Libraries/Pressability/Pressability.js b/packages/react-native/Libraries/Pressability/Pressability.js index 6a4ae91fe9f2..6a787d81ae2c 100644 --- a/packages/react-native/Libraries/Pressability/Pressability.js +++ b/packages/react-native/Libraries/Pressability/Pressability.js @@ -804,8 +804,12 @@ export default class Pressability { if (typeof this._responderID === 'number') { UIManager.measure(this._responderID, this._measureCallback); - } else { + } else if ( + ReactNativeFeatureFlags.shouldPressabilityUseNativeViewHierarchyForMeasurement() + ) { this._responderID.measureAsyncOnUI(this._measureCallback); + } else { + this._responderID.measure(this._measureCallback); } } diff --git a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js index a1f4834ec10e..94f9c5e02623 100644 --- a/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js +++ b/packages/react-native/scripts/featureflags/ReactNativeFeatureFlags.config.js @@ -1067,6 +1067,17 @@ const definitions: FeatureFlagDefinitions = { }, ossReleaseStage: 'none', }, + shouldPressabilityUseNativeViewHierarchyForMeasurement: { + defaultValue: false, + metadata: { + dateAdded: '2026-06-18', + description: + 'When enabled, Pressability measures host instances from the native view hierarchy on the UI thread instead of using shadow tree layout metrics.', + expectedReleaseValue: true, + purpose: 'experimentation', + }, + ossReleaseStage: 'none', + }, shouldUseAnimatedObjectForTransform: { defaultValue: false, metadata: { From 172379effc5e046e2372d17200873f7785ba7d52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Thu, 18 Jun 2026 09:35:23 +0200 Subject: [PATCH 09/13] chore(featureflags): regenerate pressability flag --- .../src/private/featureflags/ReactNativeFeatureFlags.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js index 71e0b730c834..52dc6768227b 100644 --- a/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js +++ b/packages/react-native/src/private/featureflags/ReactNativeFeatureFlags.js @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<68e9dbd18bfcb5e7d5cad27d8663ce66>> + * @generated SignedSource<<11f1e51c94c3e1db36cd46623b2f785a>> * @flow strict * @noformat */ @@ -40,6 +40,7 @@ export type ReactNativeFeatureFlagsJsOnly = Readonly<{ externalElementInspectionEnabled: Getter, fixVirtualizeListCollapseWindowSize: Getter, isLayoutAnimationEnabled: Getter, + shouldPressabilityUseNativeViewHierarchyForMeasurement: Getter, shouldUseAnimatedObjectForTransform: Getter, shouldUseRemoveClippedSubviewsAsDefaultOnIOS: Getter, shouldUseSetNativePropsInFabric: Getter, @@ -196,6 +197,11 @@ export const fixVirtualizeListCollapseWindowSize: Getter = createJavaSc */ export const isLayoutAnimationEnabled: Getter = createJavaScriptFlagGetter('isLayoutAnimationEnabled', true); +/** + * When enabled, Pressability measures host instances from the native view hierarchy on the UI thread instead of using shadow tree layout metrics. + */ +export const shouldPressabilityUseNativeViewHierarchyForMeasurement: Getter = createJavaScriptFlagGetter('shouldPressabilityUseNativeViewHierarchyForMeasurement', false); + /** * Enables use of AnimatedObject for animating transform values. */ From 0b83307b568ce4d8e413632bef26b8d8aa7e9e38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Thu, 18 Jun 2026 09:53:18 +0200 Subject: [PATCH 10/13] fix(pressability): resolve measurement flow errors --- .../Libraries/Pressability/Pressability.js | 11 ++++++----- .../src/private/webapis/dom/nodes/specs/NativeDOM.js | 8 ++++---- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/packages/react-native/Libraries/Pressability/Pressability.js b/packages/react-native/Libraries/Pressability/Pressability.js index 6a787d81ae2c..db2eab2534d0 100644 --- a/packages/react-native/Libraries/Pressability/Pressability.js +++ b/packages/react-native/Libraries/Pressability/Pressability.js @@ -798,18 +798,19 @@ export default class Pressability { } _measureResponderRegion(): void { - if (this._responderID == null) { + const responderID = this._responderID; + if (responderID == null) { return; } - if (typeof this._responderID === 'number') { - UIManager.measure(this._responderID, this._measureCallback); + if (typeof responderID === 'number') { + UIManager.measure(responderID, this._measureCallback); } else if ( ReactNativeFeatureFlags.shouldPressabilityUseNativeViewHierarchyForMeasurement() ) { - this._responderID.measureAsyncOnUI(this._measureCallback); + responderID.measureAsyncOnUI(this._measureCallback); } else { - this._responderID.measure(this._measureCallback); + responderID.measure(this._measureCallback); } } diff --git a/packages/react-native/src/private/webapis/dom/nodes/specs/NativeDOM.js b/packages/react-native/src/private/webapis/dom/nodes/specs/NativeDOM.js index c3fd78e9c5b1..ba823bcafaf3 100644 --- a/packages/react-native/src/private/webapis/dom/nodes/specs/NativeDOM.js +++ b/packages/react-native/src/private/webapis/dom/nodes/specs/NativeDOM.js @@ -159,9 +159,9 @@ export interface Spec extends TurboModule { onSuccess: MeasureLayoutOnSuccessCallback, ) => void; - +measureAsyncOnUI: ( - nativeElementReference: mixed, - callback: MeasureInWindowOnSuccessCallback, + readonly measureAsyncOnUI: ( + nativeElementReference: unknown, + callback: MeasureOnSuccessCallback, ) => void; /** @@ -438,7 +438,7 @@ export interface RefinedSpec { onSuccess: MeasureLayoutOnSuccessCallback, ) => void; - +measureAsyncOnUI: ( + readonly measureAsyncOnUI: ( nativeElementReference: NativeElementReference, callback: MeasureOnSuccessCallback, ) => void; From 38d1c56bda4697636b6b7886a9d96cd0623515db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Thu, 18 Jun 2026 09:53:23 +0200 Subject: [PATCH 11/13] chore(cxx-api): update measurement snapshots --- scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api | 6 ++++++ scripts/cxx-api/api-snapshots/ReactAndroidNewarchCxx.api | 6 ++++++ scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api | 6 ++++++ scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api | 7 +++++++ scripts/cxx-api/api-snapshots/ReactAppleNewarchCxx.api | 7 +++++++ scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api | 7 +++++++ scripts/cxx-api/api-snapshots/ReactCommonDebugCxx.api | 5 +++++ scripts/cxx-api/api-snapshots/ReactCommonNewarchCxx.api | 5 +++++ scripts/cxx-api/api-snapshots/ReactCommonReleaseCxx.api | 5 +++++ 9 files changed, 54 insertions(+) diff --git a/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api b/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api index c635c5ed20df..63551d8a17ca 100644 --- a/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api @@ -644,6 +644,7 @@ using facebook::react::LegacyViewManagerInteropShadowNode = facebook::react::Con using facebook::react::LineMeasureCache = facebook::react::SimpleThreadSafeCache; using facebook::react::LinesMeasurements = std::vector; using facebook::react::Logger = std::function; +using facebook::react::MeasureAsyncOnUICallback = facebook::react::AsyncCallback; using facebook::react::MeasureInWindowOnSuccessCallback = facebook::react::SyncCallback; using facebook::react::MeasureLayoutOnSuccessCallback = facebook::react::SyncCallback; using facebook::react::MeasureOnSuccessCallback = facebook::react::SyncCallback; @@ -2361,6 +2362,7 @@ class facebook::react::FabricMountingManager { public void drainPreallocateViewsQueue(); public void executeMount(const facebook::react::MountingTransaction& transaction); public void maybePreallocateShadowNode(const facebook::react::ShadowNode& shadowNode); + public void measureAsyncOnUI(const facebook::react::ShadowView& shadowView, const std::function& callback); public void onAllAnimationsComplete(); public void onAnimationStarted(); public void onSurfaceStart(facebook::react::SurfaceId surfaceId); @@ -3604,6 +3606,7 @@ class facebook::react::NativeDOM : public facebook::react::NativeDOMCxxSpec getScrollSize(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode); public std::vector getChildNodes(facebook::jsi::Runtime& rt, facebook::jsi::Value nativeNodeReference); public void measure(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, const facebook::react::MeasureOnSuccessCallback& callback); + public void measureAsyncOnUI(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, const facebook::react::MeasureAsyncOnUICallback& callback); public void measureInWindow(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, const facebook::react::MeasureInWindowOnSuccessCallback& callback); public void measureLayout(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, std::shared_ptr relativeToShadowNode, facebook::jsi::Function onFail, const facebook::react::MeasureLayoutOnSuccessCallback& onSuccess); public void releasePointerCapture(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, double pointerId); @@ -4508,6 +4511,7 @@ class facebook::react::Scheduler : public facebook::react::UIManagerDelegate { public virtual void uiManagerDidSetViewSnapshot(facebook::react::Tag sourceTag, facebook::react::Tag targetTag, facebook::react::SurfaceId surfaceId) override; public virtual void uiManagerDidStartSurface(const facebook::react::ShadowTree& shadowTree) override; public virtual void uiManagerDidUpdateShadowTree(const std::unordered_map& tagToProps) override; + public virtual void uiManagerMeasureAsyncOnUI(const std::shared_ptr& shadowNode, const std::function& callback) override; public virtual void uiManagerShouldAddEventListener(std::shared_ptr listener) final; public virtual void uiManagerShouldRemoveEventListener(const std::shared_ptr& listener) final; public virtual void uiManagerShouldSetOnSurfaceStartCallback(facebook::react::UIManagerDelegate::OnSurfaceStartCallback&& callback) override; @@ -4532,6 +4536,7 @@ class facebook::react::SchedulerDelegate { public virtual void schedulerDidSetIsJSResponder(const facebook::react::ShadowView& shadowView, bool isJSResponder, bool blockNativeResponder) = 0; public virtual void schedulerDidSetViewSnapshot(facebook::react::Tag sourceTag, facebook::react::Tag targetTag, facebook::react::SurfaceId surfaceId) = 0; public virtual void schedulerDidUpdateShadowTree(const std::unordered_map& tagToProps) = 0; + public virtual void schedulerMeasureAsyncOnUI(const facebook::react::ShadowView& shadowView, const std::function& callback) = 0; public virtual void schedulerShouldMergeReactRevision(facebook::react::SurfaceId surfaceId) = 0; public virtual void schedulerShouldRenderTransactions(const std::shared_ptr& mountingCoordinator) = 0; public virtual void schedulerShouldSynchronouslyUpdateViewOnUIThread(facebook::react::Tag tag, const folly::dynamic& props) = 0; @@ -5326,6 +5331,7 @@ class facebook::react::UIManagerDelegate { public virtual void uiManagerDidSetViewSnapshot(facebook::react::Tag sourceTag, facebook::react::Tag targetTag, facebook::react::SurfaceId surfaceId) = 0; public virtual void uiManagerDidStartSurface(const facebook::react::ShadowTree& shadowTree) = 0; public virtual void uiManagerDidUpdateShadowTree(const std::unordered_map& tagToProps) = 0; + public virtual void uiManagerMeasureAsyncOnUI(const std::shared_ptr& shadowNode, const std::function& callback) = 0; public virtual void uiManagerShouldAddEventListener(std::shared_ptr listener) = 0; public virtual void uiManagerShouldRemoveEventListener(const std::shared_ptr& listener) = 0; public virtual void uiManagerShouldSetOnSurfaceStartCallback(facebook::react::UIManagerDelegate::OnSurfaceStartCallback&& callback) = 0; diff --git a/scripts/cxx-api/api-snapshots/ReactAndroidNewarchCxx.api b/scripts/cxx-api/api-snapshots/ReactAndroidNewarchCxx.api index 3093c5ef3e1c..73cc75a421cc 100644 --- a/scripts/cxx-api/api-snapshots/ReactAndroidNewarchCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAndroidNewarchCxx.api @@ -643,6 +643,7 @@ using facebook::react::LegacyViewManagerInteropShadowNode = facebook::react::Con using facebook::react::LineMeasureCache = facebook::react::SimpleThreadSafeCache; using facebook::react::LinesMeasurements = std::vector; using facebook::react::Logger = std::function; +using facebook::react::MeasureAsyncOnUICallback = facebook::react::AsyncCallback; using facebook::react::MeasureInWindowOnSuccessCallback = facebook::react::SyncCallback; using facebook::react::MeasureLayoutOnSuccessCallback = facebook::react::SyncCallback; using facebook::react::MeasureOnSuccessCallback = facebook::react::SyncCallback; @@ -2344,6 +2345,7 @@ class facebook::react::FabricMountingManager { public void drainPreallocateViewsQueue(); public void executeMount(const facebook::react::MountingTransaction& transaction); public void maybePreallocateShadowNode(const facebook::react::ShadowNode& shadowNode); + public void measureAsyncOnUI(const facebook::react::ShadowView& shadowView, const std::function& callback); public void onAllAnimationsComplete(); public void onAnimationStarted(); public void onSurfaceStart(facebook::react::SurfaceId surfaceId); @@ -3488,6 +3490,7 @@ class facebook::react::NativeDOM : public facebook::react::NativeDOMCxxSpec getScrollSize(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode); public std::vector getChildNodes(facebook::jsi::Runtime& rt, facebook::jsi::Value nativeNodeReference); public void measure(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, const facebook::react::MeasureOnSuccessCallback& callback); + public void measureAsyncOnUI(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, const facebook::react::MeasureAsyncOnUICallback& callback); public void measureInWindow(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, const facebook::react::MeasureInWindowOnSuccessCallback& callback); public void measureLayout(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, std::shared_ptr relativeToShadowNode, facebook::jsi::Function onFail, const facebook::react::MeasureLayoutOnSuccessCallback& onSuccess); public void releasePointerCapture(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, double pointerId); @@ -4328,6 +4331,7 @@ class facebook::react::Scheduler : public facebook::react::UIManagerDelegate { public virtual void uiManagerDidSetViewSnapshot(facebook::react::Tag sourceTag, facebook::react::Tag targetTag, facebook::react::SurfaceId surfaceId) override; public virtual void uiManagerDidStartSurface(const facebook::react::ShadowTree& shadowTree) override; public virtual void uiManagerDidUpdateShadowTree(const std::unordered_map& tagToProps) override; + public virtual void uiManagerMeasureAsyncOnUI(const std::shared_ptr& shadowNode, const std::function& callback) override; public virtual void uiManagerShouldAddEventListener(std::shared_ptr listener) final; public virtual void uiManagerShouldRemoveEventListener(const std::shared_ptr& listener) final; public virtual void uiManagerShouldSetOnSurfaceStartCallback(facebook::react::UIManagerDelegate::OnSurfaceStartCallback&& callback) override; @@ -4352,6 +4356,7 @@ class facebook::react::SchedulerDelegate { public virtual void schedulerDidSetIsJSResponder(const facebook::react::ShadowView& shadowView, bool isJSResponder, bool blockNativeResponder) = 0; public virtual void schedulerDidSetViewSnapshot(facebook::react::Tag sourceTag, facebook::react::Tag targetTag, facebook::react::SurfaceId surfaceId) = 0; public virtual void schedulerDidUpdateShadowTree(const std::unordered_map& tagToProps) = 0; + public virtual void schedulerMeasureAsyncOnUI(const facebook::react::ShadowView& shadowView, const std::function& callback) = 0; public virtual void schedulerShouldMergeReactRevision(facebook::react::SurfaceId surfaceId) = 0; public virtual void schedulerShouldRenderTransactions(const std::shared_ptr& mountingCoordinator) = 0; public virtual void schedulerShouldSynchronouslyUpdateViewOnUIThread(facebook::react::Tag tag, const folly::dynamic& props) = 0; @@ -5140,6 +5145,7 @@ class facebook::react::UIManagerDelegate { public virtual void uiManagerDidSetViewSnapshot(facebook::react::Tag sourceTag, facebook::react::Tag targetTag, facebook::react::SurfaceId surfaceId) = 0; public virtual void uiManagerDidStartSurface(const facebook::react::ShadowTree& shadowTree) = 0; public virtual void uiManagerDidUpdateShadowTree(const std::unordered_map& tagToProps) = 0; + public virtual void uiManagerMeasureAsyncOnUI(const std::shared_ptr& shadowNode, const std::function& callback) = 0; public virtual void uiManagerShouldAddEventListener(std::shared_ptr listener) = 0; public virtual void uiManagerShouldRemoveEventListener(const std::shared_ptr& listener) = 0; public virtual void uiManagerShouldSetOnSurfaceStartCallback(facebook::react::UIManagerDelegate::OnSurfaceStartCallback&& callback) = 0; diff --git a/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api b/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api index bb935fb104ac..9dc2b44ccf31 100644 --- a/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api @@ -644,6 +644,7 @@ using facebook::react::LegacyViewManagerInteropShadowNode = facebook::react::Con using facebook::react::LineMeasureCache = facebook::react::SimpleThreadSafeCache; using facebook::react::LinesMeasurements = std::vector; using facebook::react::Logger = std::function; +using facebook::react::MeasureAsyncOnUICallback = facebook::react::AsyncCallback; using facebook::react::MeasureInWindowOnSuccessCallback = facebook::react::SyncCallback; using facebook::react::MeasureLayoutOnSuccessCallback = facebook::react::SyncCallback; using facebook::react::MeasureOnSuccessCallback = facebook::react::SyncCallback; @@ -2359,6 +2360,7 @@ class facebook::react::FabricMountingManager { public void drainPreallocateViewsQueue(); public void executeMount(const facebook::react::MountingTransaction& transaction); public void maybePreallocateShadowNode(const facebook::react::ShadowNode& shadowNode); + public void measureAsyncOnUI(const facebook::react::ShadowView& shadowView, const std::function& callback); public void onAllAnimationsComplete(); public void onAnimationStarted(); public void onSurfaceStart(facebook::react::SurfaceId surfaceId); @@ -3601,6 +3603,7 @@ class facebook::react::NativeDOM : public facebook::react::NativeDOMCxxSpec getScrollSize(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode); public std::vector getChildNodes(facebook::jsi::Runtime& rt, facebook::jsi::Value nativeNodeReference); public void measure(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, const facebook::react::MeasureOnSuccessCallback& callback); + public void measureAsyncOnUI(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, const facebook::react::MeasureAsyncOnUICallback& callback); public void measureInWindow(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, const facebook::react::MeasureInWindowOnSuccessCallback& callback); public void measureLayout(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, std::shared_ptr relativeToShadowNode, facebook::jsi::Function onFail, const facebook::react::MeasureLayoutOnSuccessCallback& onSuccess); public void releasePointerCapture(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, double pointerId); @@ -4505,6 +4508,7 @@ class facebook::react::Scheduler : public facebook::react::UIManagerDelegate { public virtual void uiManagerDidSetViewSnapshot(facebook::react::Tag sourceTag, facebook::react::Tag targetTag, facebook::react::SurfaceId surfaceId) override; public virtual void uiManagerDidStartSurface(const facebook::react::ShadowTree& shadowTree) override; public virtual void uiManagerDidUpdateShadowTree(const std::unordered_map& tagToProps) override; + public virtual void uiManagerMeasureAsyncOnUI(const std::shared_ptr& shadowNode, const std::function& callback) override; public virtual void uiManagerShouldAddEventListener(std::shared_ptr listener) final; public virtual void uiManagerShouldRemoveEventListener(const std::shared_ptr& listener) final; public virtual void uiManagerShouldSetOnSurfaceStartCallback(facebook::react::UIManagerDelegate::OnSurfaceStartCallback&& callback) override; @@ -4529,6 +4533,7 @@ class facebook::react::SchedulerDelegate { public virtual void schedulerDidSetIsJSResponder(const facebook::react::ShadowView& shadowView, bool isJSResponder, bool blockNativeResponder) = 0; public virtual void schedulerDidSetViewSnapshot(facebook::react::Tag sourceTag, facebook::react::Tag targetTag, facebook::react::SurfaceId surfaceId) = 0; public virtual void schedulerDidUpdateShadowTree(const std::unordered_map& tagToProps) = 0; + public virtual void schedulerMeasureAsyncOnUI(const facebook::react::ShadowView& shadowView, const std::function& callback) = 0; public virtual void schedulerShouldMergeReactRevision(facebook::react::SurfaceId surfaceId) = 0; public virtual void schedulerShouldRenderTransactions(const std::shared_ptr& mountingCoordinator) = 0; public virtual void schedulerShouldSynchronouslyUpdateViewOnUIThread(facebook::react::Tag tag, const folly::dynamic& props) = 0; @@ -5317,6 +5322,7 @@ class facebook::react::UIManagerDelegate { public virtual void uiManagerDidSetViewSnapshot(facebook::react::Tag sourceTag, facebook::react::Tag targetTag, facebook::react::SurfaceId surfaceId) = 0; public virtual void uiManagerDidStartSurface(const facebook::react::ShadowTree& shadowTree) = 0; public virtual void uiManagerDidUpdateShadowTree(const std::unordered_map& tagToProps) = 0; + public virtual void uiManagerMeasureAsyncOnUI(const std::shared_ptr& shadowNode, const std::function& callback) = 0; public virtual void uiManagerShouldAddEventListener(std::shared_ptr listener) = 0; public virtual void uiManagerShouldRemoveEventListener(const std::shared_ptr& listener) = 0; public virtual void uiManagerShouldSetOnSurfaceStartCallback(facebook::react::UIManagerDelegate::OnSurfaceStartCallback&& callback) = 0; diff --git a/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api index 632c83faba04..97ed3abb5b4f 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api @@ -1451,6 +1451,7 @@ interface RCTMountingManager : public NSObject { public virtual void attachSurfaceToView:surfaceId:(UIView* view, facebook::react::SurfaceId surfaceId); public virtual void detachSurfaceFromView:surfaceId:(UIView* view, facebook::react::SurfaceId surfaceId); public virtual void dispatchCommand:commandName:args:(ReactTag reactTag, NSString* commandName, NSArray* args); + public virtual void measureAsyncOnUI:rootView:callback:(ReactTag reactTag, UIView* rootView, const std::function& callback); public virtual void scheduleTransaction:(std::shared_ptr mountingCoordinator); public virtual void sendAccessibilityEvent:eventType:(ReactTag reactTag, NSString* eventType); public virtual void setContextContainer:(std::shared_ptr contextContainer); @@ -3000,6 +3001,7 @@ protocol RCTSchedulerDelegate { public virtual void schedulerDidSendAccessibilityEvent:eventType:(const facebook::react::ShadowView& shadowView, const std::string& eventType); public virtual void schedulerDidSetIsJSResponder:blockNativeResponder:forShadowView:(BOOL isJSResponder, BOOL blockNativeResponder, const facebook::react::ShadowView& shadowView); public virtual void schedulerDidSynchronouslyUpdateViewOnUIThread:props:(facebook::react::Tag reactTag, folly::dynamic props); + public virtual void schedulerMeasureAsyncOnUI:callback:(const facebook::react::ShadowView& shadowView, const std::function& callback); public virtual void schedulerShouldMergeReactRevision:(facebook::react::SurfaceId surfaceId); public virtual void schedulerShouldRenderTransactions:(std::shared_ptr mountingCoordinator); } @@ -3509,6 +3511,7 @@ using facebook::react::LegacyViewManagerInteropShadowNode = facebook::react::Con using facebook::react::LineMeasureCache = facebook::react::SimpleThreadSafeCache; using facebook::react::LinesMeasurements = std::vector; using facebook::react::Logger = std::function; +using facebook::react::MeasureAsyncOnUICallback = facebook::react::AsyncCallback; using facebook::react::MeasureInWindowOnSuccessCallback = facebook::react::SyncCallback; using facebook::react::MeasureLayoutOnSuccessCallback = facebook::react::SyncCallback; using facebook::react::MeasureOnSuccessCallback = facebook::react::SyncCallback; @@ -5806,6 +5809,7 @@ class facebook::react::NativeDOM : public facebook::react::NativeDOMCxxSpec getScrollSize(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode); public std::vector getChildNodes(facebook::jsi::Runtime& rt, facebook::jsi::Value nativeNodeReference); public void measure(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, const facebook::react::MeasureOnSuccessCallback& callback); + public void measureAsyncOnUI(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, const facebook::react::MeasureAsyncOnUICallback& callback); public void measureInWindow(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, const facebook::react::MeasureInWindowOnSuccessCallback& callback); public void measureLayout(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, std::shared_ptr relativeToShadowNode, facebook::jsi::Function onFail, const facebook::react::MeasureLayoutOnSuccessCallback& onSuccess); public void releasePointerCapture(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, double pointerId); @@ -6706,6 +6710,7 @@ class facebook::react::Scheduler : public facebook::react::UIManagerDelegate { public virtual void uiManagerDidSetViewSnapshot(facebook::react::Tag sourceTag, facebook::react::Tag targetTag, facebook::react::SurfaceId surfaceId) override; public virtual void uiManagerDidStartSurface(const facebook::react::ShadowTree& shadowTree) override; public virtual void uiManagerDidUpdateShadowTree(const std::unordered_map& tagToProps) override; + public virtual void uiManagerMeasureAsyncOnUI(const std::shared_ptr& shadowNode, const std::function& callback) override; public virtual void uiManagerShouldAddEventListener(std::shared_ptr listener) final; public virtual void uiManagerShouldRemoveEventListener(const std::shared_ptr& listener) final; public virtual void uiManagerShouldSetOnSurfaceStartCallback(facebook::react::UIManagerDelegate::OnSurfaceStartCallback&& callback) override; @@ -6730,6 +6735,7 @@ class facebook::react::SchedulerDelegate { public virtual void schedulerDidSetIsJSResponder(const facebook::react::ShadowView& shadowView, bool isJSResponder, bool blockNativeResponder) = 0; public virtual void schedulerDidSetViewSnapshot(facebook::react::Tag sourceTag, facebook::react::Tag targetTag, facebook::react::SurfaceId surfaceId) = 0; public virtual void schedulerDidUpdateShadowTree(const std::unordered_map& tagToProps) = 0; + public virtual void schedulerMeasureAsyncOnUI(const facebook::react::ShadowView& shadowView, const std::function& callback) = 0; public virtual void schedulerShouldMergeReactRevision(facebook::react::SurfaceId surfaceId) = 0; public virtual void schedulerShouldRenderTransactions(const std::shared_ptr& mountingCoordinator) = 0; public virtual void schedulerShouldSynchronouslyUpdateViewOnUIThread(facebook::react::Tag tag, const folly::dynamic& props) = 0; @@ -7505,6 +7511,7 @@ class facebook::react::UIManagerDelegate { public virtual void uiManagerDidSetViewSnapshot(facebook::react::Tag sourceTag, facebook::react::Tag targetTag, facebook::react::SurfaceId surfaceId) = 0; public virtual void uiManagerDidStartSurface(const facebook::react::ShadowTree& shadowTree) = 0; public virtual void uiManagerDidUpdateShadowTree(const std::unordered_map& tagToProps) = 0; + public virtual void uiManagerMeasureAsyncOnUI(const std::shared_ptr& shadowNode, const std::function& callback) = 0; public virtual void uiManagerShouldAddEventListener(std::shared_ptr listener) = 0; public virtual void uiManagerShouldRemoveEventListener(const std::shared_ptr& listener) = 0; public virtual void uiManagerShouldSetOnSurfaceStartCallback(facebook::react::UIManagerDelegate::OnSurfaceStartCallback&& callback) = 0; diff --git a/scripts/cxx-api/api-snapshots/ReactAppleNewarchCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleNewarchCxx.api index 9a6416e2c1bf..442a893bfbe5 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleNewarchCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleNewarchCxx.api @@ -1449,6 +1449,7 @@ interface RCTMountingManager : public NSObject { public virtual void attachSurfaceToView:surfaceId:(UIView* view, facebook::react::SurfaceId surfaceId); public virtual void detachSurfaceFromView:surfaceId:(UIView* view, facebook::react::SurfaceId surfaceId); public virtual void dispatchCommand:commandName:args:(ReactTag reactTag, NSString* commandName, NSArray* args); + public virtual void measureAsyncOnUI:rootView:callback:(ReactTag reactTag, UIView* rootView, const std::function& callback); public virtual void scheduleTransaction:(std::shared_ptr mountingCoordinator); public virtual void sendAccessibilityEvent:eventType:(ReactTag reactTag, NSString* eventType); public virtual void setContextContainer:(std::shared_ptr contextContainer); @@ -2988,6 +2989,7 @@ protocol RCTSchedulerDelegate { public virtual void schedulerDidSendAccessibilityEvent:eventType:(const facebook::react::ShadowView& shadowView, const std::string& eventType); public virtual void schedulerDidSetIsJSResponder:blockNativeResponder:forShadowView:(BOOL isJSResponder, BOOL blockNativeResponder, const facebook::react::ShadowView& shadowView); public virtual void schedulerDidSynchronouslyUpdateViewOnUIThread:props:(facebook::react::Tag reactTag, folly::dynamic props); + public virtual void schedulerMeasureAsyncOnUI:callback:(const facebook::react::ShadowView& shadowView, const std::function& callback); public virtual void schedulerShouldMergeReactRevision:(facebook::react::SurfaceId surfaceId); public virtual void schedulerShouldRenderTransactions:(std::shared_ptr mountingCoordinator); } @@ -3496,6 +3498,7 @@ using facebook::react::LegacyViewManagerInteropShadowNode = facebook::react::Con using facebook::react::LineMeasureCache = facebook::react::SimpleThreadSafeCache; using facebook::react::LinesMeasurements = std::vector; using facebook::react::Logger = std::function; +using facebook::react::MeasureAsyncOnUICallback = facebook::react::AsyncCallback; using facebook::react::MeasureInWindowOnSuccessCallback = facebook::react::SyncCallback; using facebook::react::MeasureLayoutOnSuccessCallback = facebook::react::SyncCallback; using facebook::react::MeasureOnSuccessCallback = facebook::react::SyncCallback; @@ -5718,6 +5721,7 @@ class facebook::react::NativeDOM : public facebook::react::NativeDOMCxxSpec getScrollSize(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode); public std::vector getChildNodes(facebook::jsi::Runtime& rt, facebook::jsi::Value nativeNodeReference); public void measure(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, const facebook::react::MeasureOnSuccessCallback& callback); + public void measureAsyncOnUI(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, const facebook::react::MeasureAsyncOnUICallback& callback); public void measureInWindow(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, const facebook::react::MeasureInWindowOnSuccessCallback& callback); public void measureLayout(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, std::shared_ptr relativeToShadowNode, facebook::jsi::Function onFail, const facebook::react::MeasureLayoutOnSuccessCallback& onSuccess); public void releasePointerCapture(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, double pointerId); @@ -6554,6 +6558,7 @@ class facebook::react::Scheduler : public facebook::react::UIManagerDelegate { public virtual void uiManagerDidSetViewSnapshot(facebook::react::Tag sourceTag, facebook::react::Tag targetTag, facebook::react::SurfaceId surfaceId) override; public virtual void uiManagerDidStartSurface(const facebook::react::ShadowTree& shadowTree) override; public virtual void uiManagerDidUpdateShadowTree(const std::unordered_map& tagToProps) override; + public virtual void uiManagerMeasureAsyncOnUI(const std::shared_ptr& shadowNode, const std::function& callback) override; public virtual void uiManagerShouldAddEventListener(std::shared_ptr listener) final; public virtual void uiManagerShouldRemoveEventListener(const std::shared_ptr& listener) final; public virtual void uiManagerShouldSetOnSurfaceStartCallback(facebook::react::UIManagerDelegate::OnSurfaceStartCallback&& callback) override; @@ -6578,6 +6583,7 @@ class facebook::react::SchedulerDelegate { public virtual void schedulerDidSetIsJSResponder(const facebook::react::ShadowView& shadowView, bool isJSResponder, bool blockNativeResponder) = 0; public virtual void schedulerDidSetViewSnapshot(facebook::react::Tag sourceTag, facebook::react::Tag targetTag, facebook::react::SurfaceId surfaceId) = 0; public virtual void schedulerDidUpdateShadowTree(const std::unordered_map& tagToProps) = 0; + public virtual void schedulerMeasureAsyncOnUI(const facebook::react::ShadowView& shadowView, const std::function& callback) = 0; public virtual void schedulerShouldMergeReactRevision(facebook::react::SurfaceId surfaceId) = 0; public virtual void schedulerShouldRenderTransactions(const std::shared_ptr& mountingCoordinator) = 0; public virtual void schedulerShouldSynchronouslyUpdateViewOnUIThread(facebook::react::Tag tag, const folly::dynamic& props) = 0; @@ -7347,6 +7353,7 @@ class facebook::react::UIManagerDelegate { public virtual void uiManagerDidSetViewSnapshot(facebook::react::Tag sourceTag, facebook::react::Tag targetTag, facebook::react::SurfaceId surfaceId) = 0; public virtual void uiManagerDidStartSurface(const facebook::react::ShadowTree& shadowTree) = 0; public virtual void uiManagerDidUpdateShadowTree(const std::unordered_map& tagToProps) = 0; + public virtual void uiManagerMeasureAsyncOnUI(const std::shared_ptr& shadowNode, const std::function& callback) = 0; public virtual void uiManagerShouldAddEventListener(std::shared_ptr listener) = 0; public virtual void uiManagerShouldRemoveEventListener(const std::shared_ptr& listener) = 0; public virtual void uiManagerShouldSetOnSurfaceStartCallback(facebook::react::UIManagerDelegate::OnSurfaceStartCallback&& callback) = 0; diff --git a/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api index a7de1287c084..557b42109765 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api @@ -1451,6 +1451,7 @@ interface RCTMountingManager : public NSObject { public virtual void attachSurfaceToView:surfaceId:(UIView* view, facebook::react::SurfaceId surfaceId); public virtual void detachSurfaceFromView:surfaceId:(UIView* view, facebook::react::SurfaceId surfaceId); public virtual void dispatchCommand:commandName:args:(ReactTag reactTag, NSString* commandName, NSArray* args); + public virtual void measureAsyncOnUI:rootView:callback:(ReactTag reactTag, UIView* rootView, const std::function& callback); public virtual void scheduleTransaction:(std::shared_ptr mountingCoordinator); public virtual void sendAccessibilityEvent:eventType:(ReactTag reactTag, NSString* eventType); public virtual void setContextContainer:(std::shared_ptr contextContainer); @@ -3000,6 +3001,7 @@ protocol RCTSchedulerDelegate { public virtual void schedulerDidSendAccessibilityEvent:eventType:(const facebook::react::ShadowView& shadowView, const std::string& eventType); public virtual void schedulerDidSetIsJSResponder:blockNativeResponder:forShadowView:(BOOL isJSResponder, BOOL blockNativeResponder, const facebook::react::ShadowView& shadowView); public virtual void schedulerDidSynchronouslyUpdateViewOnUIThread:props:(facebook::react::Tag reactTag, folly::dynamic props); + public virtual void schedulerMeasureAsyncOnUI:callback:(const facebook::react::ShadowView& shadowView, const std::function& callback); public virtual void schedulerShouldMergeReactRevision:(facebook::react::SurfaceId surfaceId); public virtual void schedulerShouldRenderTransactions:(std::shared_ptr mountingCoordinator); } @@ -3509,6 +3511,7 @@ using facebook::react::LegacyViewManagerInteropShadowNode = facebook::react::Con using facebook::react::LineMeasureCache = facebook::react::SimpleThreadSafeCache; using facebook::react::LinesMeasurements = std::vector; using facebook::react::Logger = std::function; +using facebook::react::MeasureAsyncOnUICallback = facebook::react::AsyncCallback; using facebook::react::MeasureInWindowOnSuccessCallback = facebook::react::SyncCallback; using facebook::react::MeasureLayoutOnSuccessCallback = facebook::react::SyncCallback; using facebook::react::MeasureOnSuccessCallback = facebook::react::SyncCallback; @@ -5803,6 +5806,7 @@ class facebook::react::NativeDOM : public facebook::react::NativeDOMCxxSpec getScrollSize(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode); public std::vector getChildNodes(facebook::jsi::Runtime& rt, facebook::jsi::Value nativeNodeReference); public void measure(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, const facebook::react::MeasureOnSuccessCallback& callback); + public void measureAsyncOnUI(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, const facebook::react::MeasureAsyncOnUICallback& callback); public void measureInWindow(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, const facebook::react::MeasureInWindowOnSuccessCallback& callback); public void measureLayout(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, std::shared_ptr relativeToShadowNode, facebook::jsi::Function onFail, const facebook::react::MeasureLayoutOnSuccessCallback& onSuccess); public void releasePointerCapture(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, double pointerId); @@ -6703,6 +6707,7 @@ class facebook::react::Scheduler : public facebook::react::UIManagerDelegate { public virtual void uiManagerDidSetViewSnapshot(facebook::react::Tag sourceTag, facebook::react::Tag targetTag, facebook::react::SurfaceId surfaceId) override; public virtual void uiManagerDidStartSurface(const facebook::react::ShadowTree& shadowTree) override; public virtual void uiManagerDidUpdateShadowTree(const std::unordered_map& tagToProps) override; + public virtual void uiManagerMeasureAsyncOnUI(const std::shared_ptr& shadowNode, const std::function& callback) override; public virtual void uiManagerShouldAddEventListener(std::shared_ptr listener) final; public virtual void uiManagerShouldRemoveEventListener(const std::shared_ptr& listener) final; public virtual void uiManagerShouldSetOnSurfaceStartCallback(facebook::react::UIManagerDelegate::OnSurfaceStartCallback&& callback) override; @@ -6727,6 +6732,7 @@ class facebook::react::SchedulerDelegate { public virtual void schedulerDidSetIsJSResponder(const facebook::react::ShadowView& shadowView, bool isJSResponder, bool blockNativeResponder) = 0; public virtual void schedulerDidSetViewSnapshot(facebook::react::Tag sourceTag, facebook::react::Tag targetTag, facebook::react::SurfaceId surfaceId) = 0; public virtual void schedulerDidUpdateShadowTree(const std::unordered_map& tagToProps) = 0; + public virtual void schedulerMeasureAsyncOnUI(const facebook::react::ShadowView& shadowView, const std::function& callback) = 0; public virtual void schedulerShouldMergeReactRevision(facebook::react::SurfaceId surfaceId) = 0; public virtual void schedulerShouldRenderTransactions(const std::shared_ptr& mountingCoordinator) = 0; public virtual void schedulerShouldSynchronouslyUpdateViewOnUIThread(facebook::react::Tag tag, const folly::dynamic& props) = 0; @@ -7496,6 +7502,7 @@ class facebook::react::UIManagerDelegate { public virtual void uiManagerDidSetViewSnapshot(facebook::react::Tag sourceTag, facebook::react::Tag targetTag, facebook::react::SurfaceId surfaceId) = 0; public virtual void uiManagerDidStartSurface(const facebook::react::ShadowTree& shadowTree) = 0; public virtual void uiManagerDidUpdateShadowTree(const std::unordered_map& tagToProps) = 0; + public virtual void uiManagerMeasureAsyncOnUI(const std::shared_ptr& shadowNode, const std::function& callback) = 0; public virtual void uiManagerShouldAddEventListener(std::shared_ptr listener) = 0; public virtual void uiManagerShouldRemoveEventListener(const std::shared_ptr& listener) = 0; public virtual void uiManagerShouldSetOnSurfaceStartCallback(facebook::react::UIManagerDelegate::OnSurfaceStartCallback&& callback) = 0; diff --git a/scripts/cxx-api/api-snapshots/ReactCommonDebugCxx.api b/scripts/cxx-api/api-snapshots/ReactCommonDebugCxx.api index 0a98be05bfa5..ec45d88a2540 100644 --- a/scripts/cxx-api/api-snapshots/ReactCommonDebugCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactCommonDebugCxx.api @@ -269,6 +269,7 @@ using facebook::react::LegacyViewManagerInteropShadowNode = facebook::react::Con using facebook::react::LineMeasureCache = facebook::react::SimpleThreadSafeCache; using facebook::react::LinesMeasurements = std::vector; using facebook::react::Logger = std::function; +using facebook::react::MeasureAsyncOnUICallback = facebook::react::AsyncCallback; using facebook::react::MeasureInWindowOnSuccessCallback = facebook::react::SyncCallback; using facebook::react::MeasureLayoutOnSuccessCallback = facebook::react::SyncCallback; using facebook::react::MeasureOnSuccessCallback = facebook::react::SyncCallback; @@ -2402,6 +2403,7 @@ class facebook::react::NativeDOM : public NativeDOMCxxSpec getScrollSize(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode); public std::vector getChildNodes(facebook::jsi::Runtime& rt, facebook::jsi::Value nativeNodeReference); public void measure(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, const facebook::react::MeasureOnSuccessCallback& callback); + public void measureAsyncOnUI(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, const facebook::react::MeasureAsyncOnUICallback& callback); public void measureInWindow(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, const facebook::react::MeasureInWindowOnSuccessCallback& callback); public void measureLayout(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, std::shared_ptr relativeToShadowNode, facebook::jsi::Function onFail, const facebook::react::MeasureLayoutOnSuccessCallback& onSuccess); public void releasePointerCapture(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, double pointerId); @@ -3063,6 +3065,7 @@ class facebook::react::Scheduler : public facebook::react::UIManagerDelegate { public virtual void uiManagerDidSetViewSnapshot(facebook::react::Tag sourceTag, facebook::react::Tag targetTag, facebook::react::SurfaceId surfaceId) override; public virtual void uiManagerDidStartSurface(const facebook::react::ShadowTree& shadowTree) override; public virtual void uiManagerDidUpdateShadowTree(const std::unordered_map& tagToProps) override; + public virtual void uiManagerMeasureAsyncOnUI(const std::shared_ptr& shadowNode, const std::function& callback) override; public virtual void uiManagerShouldAddEventListener(std::shared_ptr listener) final; public virtual void uiManagerShouldRemoveEventListener(const std::shared_ptr& listener) final; public virtual void uiManagerShouldSetOnSurfaceStartCallback(facebook::react::UIManagerDelegate::OnSurfaceStartCallback&& callback) override; @@ -3087,6 +3090,7 @@ class facebook::react::SchedulerDelegate { public virtual void schedulerDidSetIsJSResponder(const facebook::react::ShadowView& shadowView, bool isJSResponder, bool blockNativeResponder) = 0; public virtual void schedulerDidSetViewSnapshot(facebook::react::Tag sourceTag, facebook::react::Tag targetTag, facebook::react::SurfaceId surfaceId) = 0; public virtual void schedulerDidUpdateShadowTree(const std::unordered_map& tagToProps) = 0; + public virtual void schedulerMeasureAsyncOnUI(const facebook::react::ShadowView& shadowView, const std::function& callback) = 0; public virtual void schedulerShouldMergeReactRevision(facebook::react::SurfaceId surfaceId) = 0; public virtual void schedulerShouldRenderTransactions(const std::shared_ptr& mountingCoordinator) = 0; public virtual void schedulerShouldSynchronouslyUpdateViewOnUIThread(facebook::react::Tag tag, const folly::dynamic& props) = 0; @@ -3778,6 +3782,7 @@ class facebook::react::UIManagerDelegate { public virtual void uiManagerDidSetViewSnapshot(facebook::react::Tag sourceTag, facebook::react::Tag targetTag, facebook::react::SurfaceId surfaceId) = 0; public virtual void uiManagerDidStartSurface(const facebook::react::ShadowTree& shadowTree) = 0; public virtual void uiManagerDidUpdateShadowTree(const std::unordered_map& tagToProps) = 0; + public virtual void uiManagerMeasureAsyncOnUI(const std::shared_ptr& shadowNode, const std::function& callback) = 0; public virtual void uiManagerShouldAddEventListener(std::shared_ptr listener) = 0; public virtual void uiManagerShouldRemoveEventListener(const std::shared_ptr& listener) = 0; public virtual void uiManagerShouldSetOnSurfaceStartCallback(facebook::react::UIManagerDelegate::OnSurfaceStartCallback&& callback) = 0; diff --git a/scripts/cxx-api/api-snapshots/ReactCommonNewarchCxx.api b/scripts/cxx-api/api-snapshots/ReactCommonNewarchCxx.api index 0d05fc986ad8..3587c620a4d6 100644 --- a/scripts/cxx-api/api-snapshots/ReactCommonNewarchCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactCommonNewarchCxx.api @@ -268,6 +268,7 @@ using facebook::react::LegacyViewManagerInteropShadowNode = facebook::react::Con using facebook::react::LineMeasureCache = facebook::react::SimpleThreadSafeCache; using facebook::react::LinesMeasurements = std::vector; using facebook::react::Logger = std::function; +using facebook::react::MeasureAsyncOnUICallback = facebook::react::AsyncCallback; using facebook::react::MeasureInWindowOnSuccessCallback = facebook::react::SyncCallback; using facebook::react::MeasureLayoutOnSuccessCallback = facebook::react::SyncCallback; using facebook::react::MeasureOnSuccessCallback = facebook::react::SyncCallback; @@ -2326,6 +2327,7 @@ class facebook::react::NativeDOM : public NativeDOMCxxSpec getScrollSize(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode); public std::vector getChildNodes(facebook::jsi::Runtime& rt, facebook::jsi::Value nativeNodeReference); public void measure(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, const facebook::react::MeasureOnSuccessCallback& callback); + public void measureAsyncOnUI(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, const facebook::react::MeasureAsyncOnUICallback& callback); public void measureInWindow(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, const facebook::react::MeasureInWindowOnSuccessCallback& callback); public void measureLayout(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, std::shared_ptr relativeToShadowNode, facebook::jsi::Function onFail, const facebook::react::MeasureLayoutOnSuccessCallback& onSuccess); public void releasePointerCapture(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, double pointerId); @@ -2923,6 +2925,7 @@ class facebook::react::Scheduler : public facebook::react::UIManagerDelegate { public virtual void uiManagerDidSetViewSnapshot(facebook::react::Tag sourceTag, facebook::react::Tag targetTag, facebook::react::SurfaceId surfaceId) override; public virtual void uiManagerDidStartSurface(const facebook::react::ShadowTree& shadowTree) override; public virtual void uiManagerDidUpdateShadowTree(const std::unordered_map& tagToProps) override; + public virtual void uiManagerMeasureAsyncOnUI(const std::shared_ptr& shadowNode, const std::function& callback) override; public virtual void uiManagerShouldAddEventListener(std::shared_ptr listener) final; public virtual void uiManagerShouldRemoveEventListener(const std::shared_ptr& listener) final; public virtual void uiManagerShouldSetOnSurfaceStartCallback(facebook::react::UIManagerDelegate::OnSurfaceStartCallback&& callback) override; @@ -2947,6 +2950,7 @@ class facebook::react::SchedulerDelegate { public virtual void schedulerDidSetIsJSResponder(const facebook::react::ShadowView& shadowView, bool isJSResponder, bool blockNativeResponder) = 0; public virtual void schedulerDidSetViewSnapshot(facebook::react::Tag sourceTag, facebook::react::Tag targetTag, facebook::react::SurfaceId surfaceId) = 0; public virtual void schedulerDidUpdateShadowTree(const std::unordered_map& tagToProps) = 0; + public virtual void schedulerMeasureAsyncOnUI(const facebook::react::ShadowView& shadowView, const std::function& callback) = 0; public virtual void schedulerShouldMergeReactRevision(facebook::react::SurfaceId surfaceId) = 0; public virtual void schedulerShouldRenderTransactions(const std::shared_ptr& mountingCoordinator) = 0; public virtual void schedulerShouldSynchronouslyUpdateViewOnUIThread(facebook::react::Tag tag, const folly::dynamic& props) = 0; @@ -3632,6 +3636,7 @@ class facebook::react::UIManagerDelegate { public virtual void uiManagerDidSetViewSnapshot(facebook::react::Tag sourceTag, facebook::react::Tag targetTag, facebook::react::SurfaceId surfaceId) = 0; public virtual void uiManagerDidStartSurface(const facebook::react::ShadowTree& shadowTree) = 0; public virtual void uiManagerDidUpdateShadowTree(const std::unordered_map& tagToProps) = 0; + public virtual void uiManagerMeasureAsyncOnUI(const std::shared_ptr& shadowNode, const std::function& callback) = 0; public virtual void uiManagerShouldAddEventListener(std::shared_ptr listener) = 0; public virtual void uiManagerShouldRemoveEventListener(const std::shared_ptr& listener) = 0; public virtual void uiManagerShouldSetOnSurfaceStartCallback(facebook::react::UIManagerDelegate::OnSurfaceStartCallback&& callback) = 0; diff --git a/scripts/cxx-api/api-snapshots/ReactCommonReleaseCxx.api b/scripts/cxx-api/api-snapshots/ReactCommonReleaseCxx.api index 603463858c58..9150df96f40c 100644 --- a/scripts/cxx-api/api-snapshots/ReactCommonReleaseCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactCommonReleaseCxx.api @@ -269,6 +269,7 @@ using facebook::react::LegacyViewManagerInteropShadowNode = facebook::react::Con using facebook::react::LineMeasureCache = facebook::react::SimpleThreadSafeCache; using facebook::react::LinesMeasurements = std::vector; using facebook::react::Logger = std::function; +using facebook::react::MeasureAsyncOnUICallback = facebook::react::AsyncCallback; using facebook::react::MeasureInWindowOnSuccessCallback = facebook::react::SyncCallback; using facebook::react::MeasureLayoutOnSuccessCallback = facebook::react::SyncCallback; using facebook::react::MeasureOnSuccessCallback = facebook::react::SyncCallback; @@ -2399,6 +2400,7 @@ class facebook::react::NativeDOM : public NativeDOMCxxSpec getScrollSize(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode); public std::vector getChildNodes(facebook::jsi::Runtime& rt, facebook::jsi::Value nativeNodeReference); public void measure(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, const facebook::react::MeasureOnSuccessCallback& callback); + public void measureAsyncOnUI(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, const facebook::react::MeasureAsyncOnUICallback& callback); public void measureInWindow(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, const facebook::react::MeasureInWindowOnSuccessCallback& callback); public void measureLayout(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, std::shared_ptr relativeToShadowNode, facebook::jsi::Function onFail, const facebook::react::MeasureLayoutOnSuccessCallback& onSuccess); public void releasePointerCapture(facebook::jsi::Runtime& rt, std::shared_ptr shadowNode, double pointerId); @@ -3060,6 +3062,7 @@ class facebook::react::Scheduler : public facebook::react::UIManagerDelegate { public virtual void uiManagerDidSetViewSnapshot(facebook::react::Tag sourceTag, facebook::react::Tag targetTag, facebook::react::SurfaceId surfaceId) override; public virtual void uiManagerDidStartSurface(const facebook::react::ShadowTree& shadowTree) override; public virtual void uiManagerDidUpdateShadowTree(const std::unordered_map& tagToProps) override; + public virtual void uiManagerMeasureAsyncOnUI(const std::shared_ptr& shadowNode, const std::function& callback) override; public virtual void uiManagerShouldAddEventListener(std::shared_ptr listener) final; public virtual void uiManagerShouldRemoveEventListener(const std::shared_ptr& listener) final; public virtual void uiManagerShouldSetOnSurfaceStartCallback(facebook::react::UIManagerDelegate::OnSurfaceStartCallback&& callback) override; @@ -3084,6 +3087,7 @@ class facebook::react::SchedulerDelegate { public virtual void schedulerDidSetIsJSResponder(const facebook::react::ShadowView& shadowView, bool isJSResponder, bool blockNativeResponder) = 0; public virtual void schedulerDidSetViewSnapshot(facebook::react::Tag sourceTag, facebook::react::Tag targetTag, facebook::react::SurfaceId surfaceId) = 0; public virtual void schedulerDidUpdateShadowTree(const std::unordered_map& tagToProps) = 0; + public virtual void schedulerMeasureAsyncOnUI(const facebook::react::ShadowView& shadowView, const std::function& callback) = 0; public virtual void schedulerShouldMergeReactRevision(facebook::react::SurfaceId surfaceId) = 0; public virtual void schedulerShouldRenderTransactions(const std::shared_ptr& mountingCoordinator) = 0; public virtual void schedulerShouldSynchronouslyUpdateViewOnUIThread(facebook::react::Tag tag, const folly::dynamic& props) = 0; @@ -3769,6 +3773,7 @@ class facebook::react::UIManagerDelegate { public virtual void uiManagerDidSetViewSnapshot(facebook::react::Tag sourceTag, facebook::react::Tag targetTag, facebook::react::SurfaceId surfaceId) = 0; public virtual void uiManagerDidStartSurface(const facebook::react::ShadowTree& shadowTree) = 0; public virtual void uiManagerDidUpdateShadowTree(const std::unordered_map& tagToProps) = 0; + public virtual void uiManagerMeasureAsyncOnUI(const std::shared_ptr& shadowNode, const std::function& callback) = 0; public virtual void uiManagerShouldAddEventListener(std::shared_ptr listener) = 0; public virtual void uiManagerShouldRemoveEventListener(const std::shared_ptr& listener) = 0; public virtual void uiManagerShouldSetOnSurfaceStartCallback(facebook::react::UIManagerDelegate::OnSurfaceStartCallback&& callback) = 0; From db2e2282e22d292428768730f4eb4f62a264a154 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Thu, 18 Jun 2026 10:34:41 +0200 Subject: [PATCH 12/13] fix(ios): avoid duplicate fabric surface include --- packages/react-native/React/Fabric/Mounting/RCTMountingManager.h | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/react-native/React/Fabric/Mounting/RCTMountingManager.h b/packages/react-native/React/Fabric/Mounting/RCTMountingManager.h index 24e8fe989596..774b0a82184c 100644 --- a/packages/react-native/React/Fabric/Mounting/RCTMountingManager.h +++ b/packages/react-native/React/Fabric/Mounting/RCTMountingManager.h @@ -7,7 +7,6 @@ #import -#import #import #import #import From 57b38c6c6642e2a6c9b4e45ab768aa98642d5d6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Thu, 18 Jun 2026 10:46:52 +0200 Subject: [PATCH 13/13] chore(ci): retrigger pipeline