diff --git a/packages/react-native/React/Fabric/RCTScheduler.mm b/packages/react-native/React/Fabric/RCTScheduler.mm index 408ed9545b2d..9519f18428e4 100644 --- a/packages/react-native/React/Fabric/RCTScheduler.mm +++ b/packages/react-native/React/Fabric/RCTScheduler.mm @@ -85,6 +85,24 @@ void schedulerDidUpdateShadowTree(const std::unordered_map // This delegate method is not currently used on iOS. } + void schedulerDidCaptureViewSnapshot(Tag tag, SurfaceId surfaceId) override + { + // Does nothing. + // View transition snapshots are not currently implemented on iOS. + } + + void schedulerDidSetViewSnapshot(Tag sourceTag, Tag targetTag, SurfaceId surfaceId) override + { + // Does nothing. + // View transition snapshots are not currently implemented on iOS. + } + + void schedulerDidClearPendingSnapshots() override + { + // Does nothing. + // View transition snapshots are not currently implemented on iOS. + } + private: void *scheduler_; }; diff --git a/packages/react-native/ReactAndroid/api/ReactAndroid.api b/packages/react-native/ReactAndroid/api/ReactAndroid.api index 56b7c520ffd6..104d0feefee3 100644 --- a/packages/react-native/ReactAndroid/api/ReactAndroid.api +++ b/packages/react-native/ReactAndroid/api/ReactAndroid.api @@ -2275,6 +2275,7 @@ public final class com/facebook/react/fabric/FabricUIManagerProviderImpl : com/f public final class com/facebook/react/fabric/mounting/SurfaceMountingManager { public final fun addViewAt (III)V + public final fun applyViewSnapshot (ILandroid/graphics/Bitmap;)V public final fun attachRootView (Landroid/view/View;Lcom/facebook/react/uimanager/ThemedReactContext;)V public final fun deleteView (I)V public final fun enqueuePendingEvent (ILjava/lang/String;ZLcom/facebook/react/bridge/WritableMap;I)V 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 64d9655cba59..f6658992ec41 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 @@ -208,6 +208,8 @@ public class FabricUIManager private boolean mDriveCxxAnimations = false; + private @Nullable ViewTransitionSnapshotManager mViewTransitionSnapshotManager; + private long mDispatchViewUpdatesTime = 0l; private long mCommitStartTime = 0l; private long mLayoutTime = 0l; @@ -811,6 +813,40 @@ public void synchronouslyUpdateViewOnUIThread(final int reactTag, final Readable ReactMarkerConstants.FABRIC_UPDATE_UI_MAIN_THREAD_END, null, commitNumber); } + /** Called from C++ via JNI. */ + @SuppressLint("NotInvokedPrivateMethod") + @SuppressWarnings("unused") + @AnyThread + @ThreadConfined(ANY) + private void captureViewSnapshot(final int reactTag, final int surfaceId) { + getViewTransitionSnapshotManager().captureViewSnapshot(reactTag, surfaceId); + } + + /** Called from C++ via JNI. */ + @SuppressLint("NotInvokedPrivateMethod") + @SuppressWarnings("unused") + @AnyThread + @ThreadConfined(ANY) + private void setViewSnapshot(final int sourceTag, final int targetTag, final int surfaceId) { + getViewTransitionSnapshotManager().setViewSnapshot(sourceTag, targetTag); + } + + /** Called from C++ via JNI. */ + @SuppressLint("NotInvokedPrivateMethod") + @SuppressWarnings("unused") + @AnyThread + @ThreadConfined(ANY) + private void clearPendingSnapshots() { + getViewTransitionSnapshotManager().clearPendingSnapshots(); + } + + private synchronized ViewTransitionSnapshotManager getViewTransitionSnapshotManager() { + if (mViewTransitionSnapshotManager == null) { + mViewTransitionSnapshotManager = new ViewTransitionSnapshotManager(this, mMountingManager); + } + return mViewTransitionSnapshotManager; + } + @SuppressLint("NotInvokedPrivateMethod") @SuppressWarnings("unused") @AnyThread diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/ViewTransitionSnapshotManager.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/ViewTransitionSnapshotManager.kt new file mode 100644 index 000000000000..efd963165358 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/ViewTransitionSnapshotManager.kt @@ -0,0 +1,186 @@ +/* + * 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 + +import android.graphics.Bitmap +import android.graphics.Canvas +import android.graphics.Rect +import android.os.Build +import android.os.Handler +import android.os.Looper +import android.view.PixelCopy +import android.view.View +import android.view.Window +import androidx.annotation.RequiresApi +import androidx.annotation.UiThread +import androidx.core.graphics.createBitmap +import com.facebook.infer.annotation.ThreadConfined +import com.facebook.react.bridge.UIManager +import com.facebook.react.bridge.UIManagerListener +import com.facebook.react.bridge.UiThreadUtil +import com.facebook.react.common.annotations.UnstableReactNativeAPI +import com.facebook.react.fabric.mounting.MountingManager + +/** + * Manages bitmap snapshots of views during view transitions. Captures bitmaps from old views and + * applies them to pseudo-element shadow nodes, re-applying after each mount cycle since views may + * be recreated. Cleans up entries whose views have been deleted. + */ +@OptIn(UnstableReactNativeAPI::class) +internal class ViewTransitionSnapshotManager( + private val uiManager: FabricUIManager, + private val mountingManager: MountingManager, +) : UIManagerListener { + + companion object { + private fun captureSoftwareBitmap(view: View): Bitmap { + val bitmap = createBitmap(view.width, view.height) + view.draw(Canvas(bitmap)) + return bitmap + } + } + + // Captured bitmaps keyed by source tag. Populated by onBitmapCaptured. + @ThreadConfined(ThreadConfined.UI) private val viewSnapshots = LinkedHashMap() + + // Source→target tag mapping. Populated by setViewSnapshot. + // A snapshot is resolved when both maps contain an entry for the same source tag. + @ThreadConfined(ThreadConfined.UI) private val pendingTargets = LinkedHashMap() + + @ThreadConfined(ThreadConfined.UI) private var listenerRegistered = false + + private val mainHandler = Handler(Looper.getMainLooper()) + + @UiThread + private fun onBitmapCaptured(reactTag: Int, bitmap: Bitmap) { + viewSnapshots[reactTag] = bitmap + if (reactTag in pendingTargets) { + ensureListenerRegistered() + } + } + + @UiThread + private fun ensureListenerRegistered() { + if (!listenerRegistered) { + listenerRegistered = true + uiManager.addUIManagerEventListener(this) + } + } + + /** + * Captures a bitmap snapshot of the view identified by the given tag. On API 26+, uses PixelCopy + * to capture directly from the GPU-composited surface (faster for complex views, captures + * hardware-accelerated content). Falls back to View.draw() on older APIs. + */ + fun captureViewSnapshot(reactTag: Int, surfaceId: Int) { + UiThreadUtil.runOnUiThread { + val smm = mountingManager.getSurfaceManager(surfaceId) ?: return@runOnUiThread + if (!smm.getViewExists(reactTag)) return@runOnUiThread + val view = smm.getView(reactTag) + if (view.width <= 0 || view.height <= 0) return@runOnUiThread + + val window = + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + (view.context as? com.facebook.react.bridge.ReactContext)?.getCurrentActivity()?.window + } else { + null + } + + if (window != null) { + captureHardwareBitmap(view, reactTag, window) + } else { + // Software fallback runs synchronously, so onBitmapCaptured always + // completes before setViewSnapshot is called. + onBitmapCaptured(reactTag, captureSoftwareBitmap(view)) + } + } + } + + @RequiresApi(Build.VERSION_CODES.O) + private fun captureHardwareBitmap(view: View, reactTag: Int, window: Window) { + val bitmap = createBitmap(view.width, view.height) + val location = IntArray(2) + view.getLocationInWindow(location) + val rect = Rect(location[0], location[1], location[0] + view.width, location[1] + view.height) + // PixelCopy callback is posted to mainHandler, so onBitmapCaptured may run after + // setViewSnapshot has already recorded the target tag for this source tag. + try { + PixelCopy.request( + window, + rect, + bitmap, + { copyResult -> + if (copyResult == PixelCopy.SUCCESS) { + val hwBitmap = bitmap.copy(Bitmap.Config.HARDWARE, false) + if (hwBitmap != null) { + bitmap.recycle() + onBitmapCaptured(reactTag, hwBitmap) + } else { + onBitmapCaptured(reactTag, bitmap) + } + } else { + bitmap.recycle() + onBitmapCaptured(reactTag, captureSoftwareBitmap(view)) + } + }, + mainHandler, + ) + } catch (e: IllegalArgumentException) { + // Window surface may have been destroyed (e.g., device idle/sleep). + // Fall back to software rendering. + bitmap.recycle() + onBitmapCaptured(reactTag, captureSoftwareBitmap(view)) + } + } + + /** + * Maps a previously captured bitmap from a source view to a target pseudo-element view. If the + * bitmap is already available, the snapshot becomes resolved and will be re-applied after mount + * cycles. + */ + fun setViewSnapshot(sourceTag: Int, targetTag: Int) { + UiThreadUtil.runOnUiThread { + pendingTargets[sourceTag] = targetTag + if (sourceTag in viewSnapshots) { + ensureListenerRegistered() + } + } + } + + /** + * Clears all snapshots. Called when a view transition ends to release bitmaps and unregister the + * mount listener. + */ + fun clearPendingSnapshots() { + UiThreadUtil.runOnUiThread { + viewSnapshots.clear() + pendingTargets.clear() + if (listenerRegistered) { + listenerRegistered = false + uiManager.removeUIManagerEventListener(this) + } + } + } + + override fun willDispatchViewUpdates(uiManager: UIManager) {} + + override fun willMountItems(uiManager: UIManager) {} + + @UiThread + override fun didMountItems(uiManager: UIManager) { + for ((sourceTag, targetTag) in pendingTargets) { + val smm = mountingManager.getSurfaceManagerForView(targetTag) ?: continue + val bitmap = viewSnapshots[sourceTag] ?: continue + smm.applyViewSnapshot(targetTag, bitmap) + } + } + + override fun didDispatchMountItems(uiManager: UIManager) {} + + override fun didScheduleMountItems(uiManager: UIManager) {} +} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.kt index c09962b407cd..b535c10ce5aa 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/SurfaceMountingManager.kt @@ -8,6 +8,7 @@ package com.facebook.react.fabric.mounting import android.annotation.SuppressLint +import android.graphics.Bitmap import android.os.SystemClock import android.view.View import android.view.ViewGroup @@ -15,6 +16,7 @@ import android.view.ViewParent import androidx.annotation.AnyThread import androidx.annotation.UiThread import androidx.collection.SparseArrayCompat +import androidx.core.graphics.drawable.toDrawable import com.facebook.common.logging.FLog import com.facebook.infer.annotation.ThreadConfined import com.facebook.react.bridge.GuardedRunnable @@ -1089,6 +1091,13 @@ internal constructor( private fun getNullableViewState(reactTag: Int): ViewState? = tagToViewState[reactTag] + /** Applies a bitmap as the background of the view with the given tag, if it exists. */ + @UiThread + public fun applyViewSnapshot(tag: Int, bitmap: Bitmap) { + val view = getNullableViewState(tag)?.view ?: return + view.background = bitmap.toDrawable(view.resources) + } + public fun printSurfaceState(): Unit { FLog.e(TAG, "Views created for surface $surfaceId:") for (viewState in tagToViewState.values) { 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 2eb8986cb70c..b82bdab278c2 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 @@ -1229,6 +1229,30 @@ void FabricMountingManager::synchronouslyUpdateViewOnUIThread( synchronouslyUpdateViewOnUIThreadJNI(javaUIManager_, viewTag, propsMap); } +void FabricMountingManager::captureViewSnapshot(Tag tag, SurfaceId surfaceId) { + static auto captureViewSnapshotJNI = + JFabricUIManager::javaClassStatic()->getMethod( + "captureViewSnapshot"); + captureViewSnapshotJNI(javaUIManager_, tag, surfaceId); +} + +void FabricMountingManager::setViewSnapshot( + Tag sourceTag, + Tag targetTag, + SurfaceId surfaceId) { + static auto setViewSnapshotJNI = + JFabricUIManager::javaClassStatic()->getMethod( + "setViewSnapshot"); + setViewSnapshotJNI(javaUIManager_, sourceTag, targetTag, surfaceId); +} + +void FabricMountingManager::clearPendingSnapshots() { + static auto clearPendingSnapshotsJNI = + JFabricUIManager::javaClassStatic()->getMethod( + "clearPendingSnapshots"); + clearPendingSnapshotsJNI(javaUIManager_); +} + void FabricMountingManager::scheduleReactRevisionMerge(SurfaceId surfaceId) { static const auto scheduleReactRevisionMerge = JFabricUIManager::javaClassStatic()->getMethod( 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 50c80646783c..377880b658bb 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 @@ -68,6 +68,12 @@ class FabricMountingManager final { void synchronouslyUpdateViewOnUIThread(Tag viewTag, const folly::dynamic &props); + void captureViewSnapshot(Tag tag, SurfaceId surfaceId); + + void setViewSnapshot(Tag sourceTag, Tag targetTag, SurfaceId surfaceId); + + void clearPendingSnapshots(); + void scheduleReactRevisionMerge(SurfaceId surfaceId); private: 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 4abc6b79b379..839efa3dce53 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 @@ -797,6 +797,29 @@ void FabricUIManagerBinding::schedulerDidUpdateShadowTree( // no-op } +void FabricUIManagerBinding::schedulerDidCaptureViewSnapshot( + Tag tag, + SurfaceId surfaceId) { + if (mountingManager_) { + mountingManager_->captureViewSnapshot(tag, surfaceId); + } +} + +void FabricUIManagerBinding::schedulerDidSetViewSnapshot( + Tag sourceTag, + Tag targetTag, + SurfaceId surfaceId) { + if (mountingManager_) { + mountingManager_->setViewSnapshot(sourceTag, targetTag, surfaceId); + } +} + +void FabricUIManagerBinding::schedulerDidClearPendingSnapshots() { + if (mountingManager_) { + mountingManager_->clearPendingSnapshots(); + } +} + 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 6d129e7ffeaa..caf652d2352e 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 @@ -117,6 +117,12 @@ class FabricUIManagerBinding : public jni::HybridClass, void schedulerDidUpdateShadowTree(const std::unordered_map &tagToProps) override; + void schedulerDidCaptureViewSnapshot(Tag tag, SurfaceId surfaceId) override; + + void schedulerDidSetViewSnapshot(Tag sourceTag, Tag targetTag, SurfaceId surfaceId) override; + + void schedulerDidClearPendingSnapshots() override; + void setPixelDensity(float pointScaleFactor); void driveCxxAnimations(); diff --git a/packages/react-native/ReactCommon/react/nativemodule/viewtransition/NativeViewTransition.cpp b/packages/react-native/ReactCommon/react/nativemodule/viewtransition/NativeViewTransition.cpp index 6fb69012df42..8190c7c2f76b 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/viewtransition/NativeViewTransition.cpp +++ b/packages/react-native/ReactCommon/react/nativemodule/viewtransition/NativeViewTransition.cpp @@ -51,4 +51,20 @@ std::optional NativeViewTransition::getViewTransitionInstance( return result; } +jsi::Value NativeViewTransition::findPseudoElementShadowNodeByTag( + jsi::Runtime& rt, + double reactTag) { + auto& uiManager = UIManagerBinding::getBinding(rt)->getUIManager(); + auto* viewTransitionDelegate = uiManager.getViewTransitionDelegate(); + if (viewTransitionDelegate != nullptr) { + auto shadowNode = viewTransitionDelegate->findPseudoElementShadowNodeByTag( + static_cast(reactTag)); + if (shadowNode) { + return Bridging>::toJs(rt, shadowNode); + } + } + + return jsi::Value::null(); +} + } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/nativemodule/viewtransition/NativeViewTransition.h b/packages/react-native/ReactCommon/react/nativemodule/viewtransition/NativeViewTransition.h index bd5cb3b424f2..f3311f40bef3 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/viewtransition/NativeViewTransition.h +++ b/packages/react-native/ReactCommon/react/nativemodule/viewtransition/NativeViewTransition.h @@ -26,6 +26,8 @@ class NativeViewTransition : public NativeViewTransitionCxxSpec getViewTransitionInstance(jsi::Runtime &rt, const std::string &name, const std::string &pseudo); + + jsi::Value findPseudoElementShadowNodeByTag(jsi::Runtime &rt, double reactTag); }; } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.cpp b/packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.cpp index 3a1393ef40b0..28750e02d16f 100644 --- a/packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.cpp +++ b/packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.cpp @@ -160,9 +160,8 @@ Scheduler::Scheduler( // Initialize ViewTransitionModule if (ReactNativeFeatureFlags::viewTransitionEnabled()) { - viewTransitionModule_ = std::make_unique(); - viewTransitionModule_->setUIManager(uiManager_.get()); - uiManager_->setViewTransitionDelegate(viewTransitionModule_.get()); + viewTransitionModule_ = std::make_shared(); + viewTransitionModule_->initialize(uiManager_.get(), viewTransitionModule_); } uiManager->registerMountHook(*eventPerformanceLogger_); @@ -365,6 +364,27 @@ void Scheduler::uiManagerDidUpdateShadowTree( } } +void Scheduler::uiManagerDidCaptureViewSnapshot(Tag tag, SurfaceId surfaceId) { + if (delegate_ != nullptr) { + delegate_->schedulerDidCaptureViewSnapshot(tag, surfaceId); + } +} + +void Scheduler::uiManagerDidSetViewSnapshot( + Tag sourceTag, + Tag targetTag, + SurfaceId surfaceId) { + if (delegate_ != nullptr) { + delegate_->schedulerDidSetViewSnapshot(sourceTag, targetTag, surfaceId); + } +} + +void Scheduler::uiManagerDidClearPendingSnapshots() { + if (delegate_ != nullptr) { + delegate_->schedulerDidClearPendingSnapshots(); + } +} + void Scheduler::uiManagerShouldAddEventListener( std::shared_ptr listener) { addEventListener(listener); diff --git a/packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.h b/packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.h index ad16e3e40879..cc665dfde4b5 100644 --- a/packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.h +++ b/packages/react-native/ReactCommon/react/renderer/scheduler/Scheduler.h @@ -94,6 +94,9 @@ class Scheduler final : public UIManagerDelegate { bool blockNativeResponder) override; void uiManagerShouldSynchronouslyUpdateViewOnUIThread(Tag tag, const folly::dynamic &props) override; void uiManagerDidUpdateShadowTree(const std::unordered_map &tagToProps) override; + void uiManagerDidCaptureViewSnapshot(Tag tag, SurfaceId surfaceId) override; + void uiManagerDidSetViewSnapshot(Tag sourceTag, Tag targetTag, SurfaceId surfaceId) override; + void uiManagerDidClearPendingSnapshots() override; void uiManagerShouldAddEventListener(std::shared_ptr listener) final; void uiManagerShouldRemoveEventListener(const std::shared_ptr &listener) final; void uiManagerDidFinishReactCommit(const ShadowTree &shadowTree) override; @@ -147,7 +150,7 @@ class Scheduler final : public UIManagerDelegate { RuntimeScheduler *runtimeScheduler_{nullptr}; - std::unique_ptr viewTransitionModule_; + std::shared_ptr viewTransitionModule_; mutable std::shared_mutex onSurfaceStartCallbackMutex_; OnSurfaceStartCallback onSurfaceStartCallback_; diff --git a/packages/react-native/ReactCommon/react/renderer/scheduler/SchedulerDelegate.h b/packages/react-native/ReactCommon/react/renderer/scheduler/SchedulerDelegate.h index fafb5f90f297..06d9773e4ba5 100644 --- a/packages/react-native/ReactCommon/react/renderer/scheduler/SchedulerDelegate.h +++ b/packages/react-native/ReactCommon/react/renderer/scheduler/SchedulerDelegate.h @@ -66,6 +66,11 @@ class SchedulerDelegate { virtual void schedulerDidUpdateShadowTree(const std::unordered_map &tagToProps) = 0; + // View transition bitmap snapshot capture and application. + virtual void schedulerDidCaptureViewSnapshot(Tag tag, SurfaceId surfaceId) = 0; + virtual void schedulerDidSetViewSnapshot(Tag sourceTag, Tag targetTag, SurfaceId surfaceId) = 0; + virtual void schedulerDidClearPendingSnapshots() = 0; + virtual ~SchedulerDelegate() noexcept = default; }; diff --git a/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerBinding.cpp b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerBinding.cpp index 1aa9fdf2ab24..9b6b08f4642b 100644 --- a/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerBinding.cpp +++ b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerBinding.cpp @@ -981,6 +981,37 @@ jsi::Value UIManagerBinding::get( }); } + if (methodName == "createViewTransitionInstance") { + auto paramCount = 2; + return jsi::Function::createFromHostFunction( + runtime, + name, + paramCount, + [uiManager, methodName, paramCount]( + jsi::Runtime& runtime, + const jsi::Value& /*thisValue*/, + const jsi::Value* arguments, + size_t count) -> jsi::Value { + validateArgumentCount(runtime, methodName, paramCount, count); + + auto transitionName = arguments[0].isString() + ? stringFromValue(runtime, arguments[0]) + : ""; + auto pseudoElementTag = tagFromValue(arguments[1]); + + if (!transitionName.empty()) { + auto* viewTransitionDelegate = + uiManager->getViewTransitionDelegate(); + if (viewTransitionDelegate != nullptr) { + viewTransitionDelegate->createViewTransitionInstance( + transitionName, pseudoElementTag); + } + } + + return jsi::Value::undefined(); + }); + } + if (methodName == "cancelViewTransitionName") { auto paramCount = 2; return jsi::Function::createFromHostFunction( diff --git a/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerDelegate.h b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerDelegate.h index 92ee339f0929..235b1fe34eac 100644 --- a/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerDelegate.h +++ b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerDelegate.h @@ -97,6 +97,11 @@ class UIManagerDelegate { using OnSurfaceStartCallback = std::function; virtual void uiManagerShouldSetOnSurfaceStartCallback(OnSurfaceStartCallback &&callback) = 0; + // View transition bitmap snapshot capture and application. + virtual void uiManagerDidCaptureViewSnapshot(Tag tag, SurfaceId surfaceId) = 0; + virtual void uiManagerDidSetViewSnapshot(Tag sourceTag, Tag targetTag, SurfaceId surfaceId) = 0; + virtual void uiManagerDidClearPendingSnapshots() = 0; + virtual ~UIManagerDelegate() noexcept = default; }; diff --git a/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerViewTransitionDelegate.h b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerViewTransitionDelegate.h index 9d4d83637f4c..d3685775c353 100644 --- a/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerViewTransitionDelegate.h +++ b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerViewTransitionDelegate.h @@ -23,6 +23,8 @@ class UIManagerViewTransitionDelegate { { } + virtual void createViewTransitionInstance(const std::string & /*name*/, Tag /*pseudoElementTag*/) {} + virtual void cancelViewTransitionName(const ShadowNode &shadowNode, const std::string &name) {} virtual void restoreViewTransitionName(const ShadowNode &shadowNode) {} @@ -55,6 +57,16 @@ class UIManagerViewTransitionDelegate { { return std::nullopt; } + + // Similar to UIManager::findShadowNodeByTag, but searches all direct children + // of the root node (where pseudo-element nodes live) rather than just the + // first child. Pseudo-element nodes are appended as additional children of the + // root node, rather than inserted into the main React tree, to avoid + // disrupting the user-created component tree. + virtual std::shared_ptr findPseudoElementShadowNodeByTag(Tag /*tag*/) const + { + return nullptr; + } }; } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/viewtransition/ViewTransitionModule.cpp b/packages/react-native/ReactCommon/react/renderer/viewtransition/ViewTransitionModule.cpp index b4d759bf4950..ee14c7bd5851 100644 --- a/packages/react-native/ReactCommon/react/renderer/viewtransition/ViewTransitionModule.cpp +++ b/packages/react-native/ReactCommon/react/renderer/viewtransition/ViewTransitionModule.cpp @@ -7,15 +7,51 @@ #include "ViewTransitionModule.h" -#include - +#include #include +#include +#include +#include #include namespace facebook::react { -void ViewTransitionModule::setUIManager(UIManager* uiManager) { +ViewTransitionModule::~ViewTransitionModule() { + if (uiManager_ != nullptr) { + if (uiManager_->getViewTransitionDelegate() == this) { + uiManager_->setViewTransitionDelegate(nullptr); + } + uiManager_->unregisterCommitHook(*this); + uiManager_ = nullptr; + } +} + +void ViewTransitionModule::initialize( + UIManager* uiManager, + std::weak_ptr weakThis) { + if (uiManager_ != nullptr) { + uiManager_->unregisterCommitHook(*this); + } uiManager_ = uiManager; + if (uiManager_ != nullptr) { + uiManager_->registerCommitHook(*this); + + // Register as MountingOverrideDelegate on existing surfaces + uiManager_->getShadowTreeRegistry().enumerate( + [weakThis](const ShadowTree& shadowTree, bool& /*stop*/) { + shadowTree.getMountingCoordinator()->setMountingOverrideDelegate( + weakThis); + }); + + // Register on surfaces started in the future + uiManager_->setOnSurfaceStartCallback( + [weakThis](const ShadowTree& shadowTree) { + shadowTree.getMountingCoordinator()->setMountingOverrideDelegate( + weakThis); + }); + + uiManager_->setViewTransitionDelegate(this); + } } void ViewTransitionModule::applyViewTransitionName( @@ -45,6 +81,21 @@ void ViewTransitionModule::applyViewTransitionName( AnimationKeyFrameView oldView{ .layoutMetrics = keyframeMetrics, .tag = tag, .surfaceId = surfaceId}; oldLayout_[name] = oldView; + + // Request the platform to capture a bitmap snapshot of the old view + // while it's still mounted. The platform stores the bitmap keyed by tag. + if (uiManager_ != nullptr) { + auto* delegate = uiManager_->getDelegate(); + if (delegate != nullptr) { + delegate->uiManagerDidCaptureViewSnapshot(tag, surfaceId); + } + } + + if (auto it = oldPseudoElementNodesRepository_.find(name); + it != oldPseudoElementNodesRepository_.end()) { + oldPseudoElementNodes_[name] = it->second.node; + } + } else { AnimationKeyFrameView newView{ .layoutMetrics = keyframeMetrics, .tag = tag, .surfaceId = surfaceId}; @@ -52,6 +103,167 @@ void ViewTransitionModule::applyViewTransitionName( } } +void ViewTransitionModule::createViewTransitionInstance( + const std::string& name, + Tag pseudoElementTag) { + if (uiManager_ == nullptr) { + return; + } + + // if createViewTransitionInstance is called before transition started, it + // creates the old pseudo elements for exiting nodes that potentially + // participate in current transition that's about to happen; if called after + // transition started, it creates old pseudo elements for entering nodes, and + // will be used in next transition when these node are exiting + bool forNextTransition = false; + AnimationKeyFrameView view = {}; + auto it = oldLayout_.find(name); + if (it == oldLayout_.end()) { + forNextTransition = true; + if (auto newIt = newLayout_.find(name); newIt != newLayout_.end()) { + view = newIt->second; + } + } else { + view = it->second; + } + + // Build props: absolute position matching old element, non-interactive + if (pseudoElementTag > 0 && view.tag > 0) { + // Create a base node with layout props via createNode + // TODO: T262559684 created dedicated shadow node type for old pseudo + // element + auto rawProps = RawProps( + folly::dynamic::object("position", "absolute")( + "left", view.layoutMetrics.originFromRoot.x)( + "top", view.layoutMetrics.originFromRoot.y)( + "width", view.layoutMetrics.size.width)( + "height", view.layoutMetrics.size.height)("pointerEvents", "none")( + "opacity", 0)("collapsable", false)); + + auto baseNode = uiManager_->createNode( + pseudoElementTag, + "View", + view.surfaceId, + std::move(rawProps), + nullptr /* instanceHandle */); + + if (baseNode == nullptr) { + return; + } + + // Clone the shadow node — bitmap will be set by platform + auto pseudoElementNode = baseNode->clone({}); + + if (pseudoElementNode != nullptr) { + if (!forNextTransition) { + oldPseudoElementNodes_[name] = pseudoElementNode; + } + oldPseudoElementNodesRepository_[name] = InactivePseudoElement{ + .node = pseudoElementNode, .sourceTag = view.tag}; + } + } +} + +RootShadowNode::Unshared ViewTransitionModule::shadowTreeWillCommit( + const ShadowTree& shadowTree, + const RootShadowNode::Shared& /*oldRootShadowNode*/, + const RootShadowNode::Unshared& newRootShadowNode, + const ShadowTreeCommitOptions& /*commitOptions*/) noexcept { + if (oldPseudoElementNodes_.empty()) { + return newRootShadowNode; + } + + auto surfaceId = shadowTree.getSurfaceId(); + + // Collect pseudo-element nodes for this surface, skipping any that are + // already present in the children list (from a previous commit hook run). + const auto& existingChildren = newRootShadowNode->getChildren(); + std::unordered_set existingTags; + existingTags.reserve(existingChildren.size()); + for (const auto& child : existingChildren) { + existingTags.insert(child->getTag()); + } + + auto newChildren = + std::make_shared>>( + existingChildren); + bool appended = false; + for (const auto& [name, node] : oldPseudoElementNodes_) { + if (node->getSurfaceId() == surfaceId && + existingTags.find(node->getTag()) == existingTags.end()) { + newChildren->push_back(node); + appended = true; + } + } + + if (!appended) { + return newRootShadowNode; + } + + return std::make_shared( + *newRootShadowNode, + ShadowNodeFragment{ + .props = ShadowNodeFragment::propsPlaceholder(), + .children = newChildren, + }); +} + +bool ViewTransitionModule::shouldOverridePullTransaction() const { + return !oldPseudoElementNodesRepository_.empty(); +} + +std::optional ViewTransitionModule::pullTransaction( + SurfaceId surfaceId, + MountingTransaction::Number number, + const TransactionTelemetry& telemetry, + ShadowViewMutationList mutations) const { + for (const auto& mutation : mutations) { + if (mutation.type == ShadowViewMutation::Delete) { + auto tag = mutation.oldChildShadowView.tag; + for (auto it = oldPseudoElementNodesRepository_.begin(); + it != oldPseudoElementNodesRepository_.end();) { + if (it->second.sourceTag == tag) { + it = oldPseudoElementNodesRepository_.erase(it); + } else { + ++it; + } + } + } + } + return MountingTransaction{ + surfaceId, number, std::move(mutations), telemetry}; +} + +std::shared_ptr +ViewTransitionModule::findPseudoElementShadowNodeByTag(Tag tag) const { + if (uiManager_ == nullptr) { + return nullptr; + } + + auto shadowNode = std::shared_ptr{}; + + uiManager_->getShadowTreeRegistry().enumerate( + [&](const ShadowTree& shadowTree, bool& stop) { + const auto rootShadowNode = + shadowTree.getCurrentRevision().rootShadowNode; + + if (rootShadowNode != nullptr) { + const auto& children = rootShadowNode->getChildren(); + // Pseudo element nodes are appended after the first child (the main + // React tree), so iterate from index 1 onwards. + for (size_t i = 1; i < children.size(); ++i) { + if (children[i]->getTag() == tag) { + shadowNode = children[i]; + stop = true; + return; + } + } + } + }); + + return shadowNode; +} + void ViewTransitionModule::cancelViewTransitionName( const ShadowNode& shadowNode, const std::string& name) { @@ -67,6 +279,25 @@ void ViewTransitionModule::restoreViewTransitionName( cancelledNameRegistry_.erase(shadowNode.getTag()); } +void ViewTransitionModule::applySnapshotsOnPseudoElementShadowNodes() { + if (oldPseudoElementNodes_.empty() || uiManager_ == nullptr) { + return; + } + + // Set view snapshots — the pseudo-element nodes themselves will be committed + // through the normal completeRoot flow via getPseudoElementNodes(). + auto* delegate = uiManager_->getDelegate(); + if (delegate != nullptr) { + for (const auto& [name, node] : oldPseudoElementNodes_) { + auto layoutIt = oldLayout_.find(name); + if (layoutIt != oldLayout_.end()) { + delegate->uiManagerDidSetViewSnapshot( + layoutIt->second.tag, node->getTag(), node->getSurfaceId()); + } + } + } +} + LayoutMetrics ViewTransitionModule::captureLayoutMetricsFromRoot( const ShadowNode& shadowNode) { if (uiManager_ == nullptr) { @@ -100,13 +331,13 @@ void ViewTransitionModule::startViewTransition( // Mark transition as started transitionStarted_ = true; - // Call mutation callback (including commitRoot, measureInstance - // applyViewTransitionName for old & new) + // Call mutation callback (including commitRoot, measureInstance, + // applyViewTransitionName, createViewTransitionInstance for old & new) if (mutationCallback) { mutationCallback(); } - // TODO: capture pseudo elements + applySnapshotsOnPseudoElementShadowNodes(); if (onReadyCallback) { onReadyCallback(); @@ -128,6 +359,15 @@ void ViewTransitionModule::startViewTransitionEnd() { } } nameRegistry_.clear(); + oldPseudoElementNodes_.clear(); + + // Clear any pending bitmap snapshots that were captured but never consumed. + if (uiManager_ != nullptr) { + auto* delegate = uiManager_->getDelegate(); + if (delegate != nullptr) { + delegate->uiManagerDidClearPendingSnapshots(); + } + } transitionStarted_ = false; } @@ -152,12 +392,16 @@ ViewTransitionModule::getViewTransitionInstance( auto it = oldLayout_.find(name); if (it != oldLayout_.end()) { const auto& view = it->second; + auto pseudoElementIt = oldPseudoElementNodes_.find(name); + auto nativeTag = pseudoElementIt != oldPseudoElementNodes_.end() + ? pseudoElementIt->second->getTag() + : view.tag; return ViewTransitionInstance{ .x = view.layoutMetrics.originFromRoot.x, .y = view.layoutMetrics.originFromRoot.y, .width = view.layoutMetrics.size.width, .height = view.layoutMetrics.size.height, - .nativeTag = view.tag}; + .nativeTag = nativeTag}; } } diff --git a/packages/react-native/ReactCommon/react/renderer/viewtransition/ViewTransitionModule.h b/packages/react-native/ReactCommon/react/renderer/viewtransition/ViewTransitionModule.h index f5d1f59fdc50..ae585978b409 100644 --- a/packages/react-native/ReactCommon/react/renderer/viewtransition/ViewTransitionModule.h +++ b/packages/react-native/ReactCommon/react/renderer/viewtransition/ViewTransitionModule.h @@ -11,24 +11,35 @@ #include #include +#include #include +#include #include namespace facebook::react { +class ShadowTree; class UIManager; -class ViewTransitionModule : public UIManagerViewTransitionDelegate { +class ViewTransitionModule : public UIManagerViewTransitionDelegate, + public UIManagerCommitHook, + public MountingOverrideDelegate { public: - ~ViewTransitionModule() override = default; + ~ViewTransitionModule() override; - void setUIManager(UIManager *uiManager); + void initialize(UIManager *uiManager, std::weak_ptr weakThis); + +#pragma mark - UIManagerViewTransitionDelegate // will be called when a view will transition. if a view already has a view-transition-name, it may not be called // again until it's removed void applyViewTransitionName(const ShadowNode &shadowNode, const std::string &name, const std::string &className) override; + // creates a pseudo-element shadow node for a given transition name using the + // captured old layout metrics + void createViewTransitionInstance(const std::string &name, Tag pseudoElementTag) override; + // if a viewTransitionName is cancelled, the element doesn't have view-transition-name and browser won't be taking // snapshot void cancelViewTransitionName(const ShadowNode &shadowNode, const std::string &name) override; @@ -46,6 +57,27 @@ class ViewTransitionModule : public UIManagerViewTransitionDelegate { std::optional getViewTransitionInstance(const std::string &name, const std::string &pseudo) override; +#pragma mark - UIManagerCommitHook + + void commitHookWasRegistered(const UIManager & /*uiManager*/) noexcept override {} + void commitHookWasUnregistered(const UIManager & /*uiManager*/) noexcept override {} + RootShadowNode::Unshared shadowTreeWillCommit( + const ShadowTree &shadowTree, + const RootShadowNode::Shared &oldRootShadowNode, + const RootShadowNode::Unshared &newRootShadowNode, + const ShadowTreeCommitOptions &commitOptions) noexcept override; + +#pragma mark - MountingOverrideDelegate + + bool shouldOverridePullTransaction() const override; + std::optional pullTransaction( + SurfaceId surfaceId, + MountingTransaction::Number number, + const TransactionTelemetry &telemetry, + ShadowViewMutationList mutations) const override; + + std::shared_ptr findPseudoElementShadowNodeByTag(Tag tag) const override; + // Animation state structure for storing minimal view data struct AnimationKeyFrameViewLayoutMetrics { Point originFromRoot; @@ -72,8 +104,23 @@ class ViewTransitionModule : public UIManagerViewTransitionDelegate { // used for cancel/restore viewTransitionName std::unordered_map> cancelledNameRegistry_{}; + // pseudo-element nodes keyed by transition name, appended to root children via UIManagerCommitHook + // TODO: T262559264 pseudo elements should be cleaned up as soon as transition animation ends + std::unordered_map> oldPseudoElementNodes_{}; + + struct InactivePseudoElement { + std::shared_ptr node; + Tag sourceTag{0}; // tag of the original view this was created from + }; + // pseudo-element nodes created for entering nodes, to be copied into + // oldPseudoElementNodes_ during the next applyViewTransitionName call. + // Mutable because pullTransaction (const) needs to erase unmounted entries. + mutable std::unordered_map oldPseudoElementNodesRepository_{}; + LayoutMetrics captureLayoutMetricsFromRoot(const ShadowNode &shadowNode); + void applySnapshotsOnPseudoElementShadowNodes(); + UIManager *uiManager_{nullptr}; bool transitionStarted_{false}; diff --git a/packages/react-native/ReactCxxPlatform/react/renderer/scheduler/SchedulerDelegateImpl.cpp b/packages/react-native/ReactCxxPlatform/react/renderer/scheduler/SchedulerDelegateImpl.cpp index dcc1df6a5cdf..9ad1bb1a4f54 100644 --- a/packages/react-native/ReactCxxPlatform/react/renderer/scheduler/SchedulerDelegateImpl.cpp +++ b/packages/react-native/ReactCxxPlatform/react/renderer/scheduler/SchedulerDelegateImpl.cpp @@ -76,4 +76,15 @@ void SchedulerDelegateImpl::schedulerDidUpdateShadowTree( mountingManager_->onUpdateShadowTree(tagToProps); } +void SchedulerDelegateImpl::schedulerDidCaptureViewSnapshot( + Tag /*tag*/, + SurfaceId /*surfaceId*/) {} + +void SchedulerDelegateImpl::schedulerDidSetViewSnapshot( + Tag /*sourceTag*/, + Tag /*targetTag*/, + SurfaceId /*surfaceId*/) {} + +void SchedulerDelegateImpl::schedulerDidClearPendingSnapshots() {} + } // 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 b60f33962ce9..089b64d5731c 100644 --- a/packages/react-native/ReactCxxPlatform/react/renderer/scheduler/SchedulerDelegateImpl.h +++ b/packages/react-native/ReactCxxPlatform/react/renderer/scheduler/SchedulerDelegateImpl.h @@ -51,6 +51,12 @@ class SchedulerDelegateImpl : public SchedulerDelegate { void schedulerDidUpdateShadowTree(const std::unordered_map &tagToProps) override; + void schedulerDidCaptureViewSnapshot(Tag tag, SurfaceId surfaceId) override; + + void schedulerDidSetViewSnapshot(Tag sourceTag, Tag targetTag, SurfaceId surfaceId) override; + + void schedulerDidClearPendingSnapshots() override; + std::shared_ptr mountingManager_; std::shared_ptr uiManager_; }; diff --git a/packages/react-native/src/private/viewtransition/specs/NativeViewTransition.js b/packages/react-native/src/private/viewtransition/specs/NativeViewTransition.js index 1c56f51e1f3e..c9fa79cd3639 100644 --- a/packages/react-native/src/private/viewtransition/specs/NativeViewTransition.js +++ b/packages/react-native/src/private/viewtransition/specs/NativeViewTransition.js @@ -23,6 +23,7 @@ export interface Spec extends TurboModule { height: number, nativeTag: number, }; + +findPseudoElementShadowNodeByTag: (reactTag: number) => ?unknown /* Node */; } export default TurboModuleRegistry.get( diff --git a/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api b/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api index 0262c22621f0..725830820727 100644 --- a/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api @@ -2325,6 +2325,7 @@ class facebook::react::FabricMountingManager { public void scheduleReactRevisionMerge(facebook::react::SurfaceId surfaceId); public void sendAccessibilityEvent(const facebook::react::ShadowView& shadowView, const std::string& eventType); public void setIsJSResponder(const facebook::react::ShadowView& shadowView, bool isJSResponder, bool blockNativeResponder); + public void setViewSnapshot(facebook::react::Tag sourceTag, facebook::react::Tag targetTag, facebook::react::SurfaceId surfaceId); public void synchronouslyUpdateViewOnUIThread(facebook::react::Tag viewTag, const folly::dynamic& props); public ~FabricMountingManager(); } @@ -4453,6 +4454,8 @@ class facebook::react::Scheduler : public facebook::react::UIManagerDelegate { public facebook::react::SchedulerDelegate* getDelegate() const; public std::shared_ptr getContextContainer() const; public std::shared_ptr getUIManager() const; + public virtual void uiManagerDidCaptureViewSnapshot(facebook::react::Tag tag, facebook::react::SurfaceId surfaceId) override; + public virtual void uiManagerDidClearPendingSnapshots() override; public virtual void uiManagerDidCreateShadowNode(const facebook::react::ShadowNode& shadowNode) override; public virtual void uiManagerDidDispatchCommand(const std::shared_ptr& shadowNode, const std::string& commandName, const folly::dynamic& args) override; public virtual void uiManagerDidFinishReactCommit(const facebook::react::ShadowTree& shadowTree) override; @@ -4460,6 +4463,7 @@ class facebook::react::Scheduler : public facebook::react::UIManagerDelegate { public virtual void uiManagerDidPromoteReactRevision(const facebook::react::ShadowTree& shadowTree) override; public virtual void uiManagerDidSendAccessibilityEvent(const std::shared_ptr& shadowNode, const std::string& eventType) override; public virtual void uiManagerDidSetIsJSResponder(const std::shared_ptr& shadowNode, bool isJSResponder, bool blockNativeResponder) override; + 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 uiManagerShouldAddEventListener(std::shared_ptr listener) final; @@ -4477,11 +4481,14 @@ class facebook::react::Scheduler : public facebook::react::UIManagerDelegate { } class facebook::react::SchedulerDelegate { + public virtual void schedulerDidCaptureViewSnapshot(facebook::react::Tag tag, facebook::react::SurfaceId surfaceId) = 0; + public virtual void schedulerDidClearPendingSnapshots() = 0; public virtual void schedulerDidDispatchCommand(const facebook::react::ShadowView& shadowView, const std::string& commandName, const folly::dynamic& args) = 0; public virtual void schedulerDidFinishTransaction(const std::shared_ptr& mountingCoordinator) = 0; public virtual void schedulerDidRequestPreliminaryViewAllocation(const facebook::react::ShadowNode& shadowNode) = 0; public virtual void schedulerDidSendAccessibilityEvent(const facebook::react::ShadowView& shadowView, const std::string& eventType) = 0; 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 schedulerShouldMergeReactRevision(facebook::react::SurfaceId surfaceId) = 0; public virtual void schedulerShouldRenderTransactions(const std::shared_ptr& mountingCoordinator) = 0; @@ -5250,6 +5257,8 @@ class facebook::react::UIManagerCommitHook { class facebook::react::UIManagerDelegate { public using OnSurfaceStartCallback = std::function; + public virtual void uiManagerDidCaptureViewSnapshot(facebook::react::Tag tag, facebook::react::SurfaceId surfaceId) = 0; + public virtual void uiManagerDidClearPendingSnapshots() = 0; public virtual void uiManagerDidCreateShadowNode(const facebook::react::ShadowNode& shadowNode) = 0; public virtual void uiManagerDidDispatchCommand(const std::shared_ptr& shadowNode, const std::string& commandName, const folly::dynamic& args) = 0; public virtual void uiManagerDidFinishReactCommit(const facebook::react::ShadowTree& shadowTree) = 0; @@ -5257,6 +5266,7 @@ class facebook::react::UIManagerDelegate { public virtual void uiManagerDidPromoteReactRevision(const facebook::react::ShadowTree& shadowTree) = 0; public virtual void uiManagerDidSendAccessibilityEvent(const std::shared_ptr& shadowNode, const std::string& eventType) = 0; public virtual void uiManagerDidSetIsJSResponder(const std::shared_ptr& shadowNode, bool isJSResponder, bool blockNativeResponder) = 0; + 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 uiManagerShouldAddEventListener(std::shared_ptr listener) = 0; @@ -5284,8 +5294,10 @@ class facebook::react::UIManagerNativeAnimatedDelegateImpl : public facebook::re class facebook::react::UIManagerViewTransitionDelegate { public virtual std::optional getViewTransitionInstance(const std::string& name, const std::string& pseudo); + public virtual std::shared_ptr findPseudoElementShadowNodeByTag(facebook::react::Tag tag) const; public virtual void applyViewTransitionName(const facebook::react::ShadowNode& shadowNode, const std::string& name, const std::string& className); public virtual void cancelViewTransitionName(const facebook::react::ShadowNode& shadowNode, const std::string& name); + public virtual void createViewTransitionInstance(const std::string& name, facebook::react::Tag pseudoElementTag); public virtual void restoreViewTransitionName(const facebook::react::ShadowNode& shadowNode); public virtual void startViewTransition(std::function mutationCallback, std::function onReadyCallback, std::function onCompleteCallback); public virtual void startViewTransitionEnd(); @@ -5358,10 +5370,15 @@ class facebook::react::ViewShadowNodeProps : public facebook::react::HostPlatfor public ViewShadowNodeProps(const facebook::react::PropsParserContext& context, const facebook::react::ViewShadowNodeProps& sourceProps, const facebook::react::RawProps& rawProps); } -class facebook::react::ViewTransitionModule : public facebook::react::UIManagerViewTransitionDelegate { +class facebook::react::ViewTransitionModule : public facebook::react::UIManagerViewTransitionDelegate, public facebook::react::UIManagerCommitHook { + public virtual facebook::react::RootShadowNode::Unshared shadowTreeWillCommit(const facebook::react::ShadowTree& shadowTree, const facebook::react::RootShadowNode::Shared& oldRootShadowNode, const facebook::react::RootShadowNode::Unshared& newRootShadowNode, const facebook::react::ShadowTreeCommitOptions& commitOptions) noexcept override; public virtual std::optional getViewTransitionInstance(const std::string& name, const std::string& pseudo) override; + public virtual std::shared_ptr findPseudoElementShadowNodeByTag(facebook::react::Tag tag) const override; public virtual void applyViewTransitionName(const facebook::react::ShadowNode& shadowNode, const std::string& name, const std::string& className) override; public virtual void cancelViewTransitionName(const facebook::react::ShadowNode& shadowNode, const std::string& name) override; + public virtual void commitHookWasRegistered(const facebook::react::UIManager& uiManager) noexcept override; + public virtual void commitHookWasUnregistered(const facebook::react::UIManager& uiManager) noexcept override; + public virtual void createViewTransitionInstance(const std::string& name, facebook::react::Tag pseudoElementTag) override; public virtual void restoreViewTransitionName(const facebook::react::ShadowNode& shadowNode) override; public virtual void startViewTransition(std::function mutationCallback, std::function onReadyCallback, std::function onCompleteCallback) override; public virtual void startViewTransitionEnd() override; diff --git a/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api b/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api index e8bcf55187c8..3d481c044fc5 100644 --- a/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api @@ -2323,6 +2323,7 @@ class facebook::react::FabricMountingManager { public void scheduleReactRevisionMerge(facebook::react::SurfaceId surfaceId); public void sendAccessibilityEvent(const facebook::react::ShadowView& shadowView, const std::string& eventType); public void setIsJSResponder(const facebook::react::ShadowView& shadowView, bool isJSResponder, bool blockNativeResponder); + public void setViewSnapshot(facebook::react::Tag sourceTag, facebook::react::Tag targetTag, facebook::react::SurfaceId surfaceId); public void synchronouslyUpdateViewOnUIThread(facebook::react::Tag viewTag, const folly::dynamic& props); public ~FabricMountingManager(); } @@ -4450,6 +4451,8 @@ class facebook::react::Scheduler : public facebook::react::UIManagerDelegate { public facebook::react::SchedulerDelegate* getDelegate() const; public std::shared_ptr getContextContainer() const; public std::shared_ptr getUIManager() const; + public virtual void uiManagerDidCaptureViewSnapshot(facebook::react::Tag tag, facebook::react::SurfaceId surfaceId) override; + public virtual void uiManagerDidClearPendingSnapshots() override; public virtual void uiManagerDidCreateShadowNode(const facebook::react::ShadowNode& shadowNode) override; public virtual void uiManagerDidDispatchCommand(const std::shared_ptr& shadowNode, const std::string& commandName, const folly::dynamic& args) override; public virtual void uiManagerDidFinishReactCommit(const facebook::react::ShadowTree& shadowTree) override; @@ -4457,6 +4460,7 @@ class facebook::react::Scheduler : public facebook::react::UIManagerDelegate { public virtual void uiManagerDidPromoteReactRevision(const facebook::react::ShadowTree& shadowTree) override; public virtual void uiManagerDidSendAccessibilityEvent(const std::shared_ptr& shadowNode, const std::string& eventType) override; public virtual void uiManagerDidSetIsJSResponder(const std::shared_ptr& shadowNode, bool isJSResponder, bool blockNativeResponder) override; + 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 uiManagerShouldAddEventListener(std::shared_ptr listener) final; @@ -4474,11 +4478,14 @@ class facebook::react::Scheduler : public facebook::react::UIManagerDelegate { } class facebook::react::SchedulerDelegate { + public virtual void schedulerDidCaptureViewSnapshot(facebook::react::Tag tag, facebook::react::SurfaceId surfaceId) = 0; + public virtual void schedulerDidClearPendingSnapshots() = 0; public virtual void schedulerDidDispatchCommand(const facebook::react::ShadowView& shadowView, const std::string& commandName, const folly::dynamic& args) = 0; public virtual void schedulerDidFinishTransaction(const std::shared_ptr& mountingCoordinator) = 0; public virtual void schedulerDidRequestPreliminaryViewAllocation(const facebook::react::ShadowNode& shadowNode) = 0; public virtual void schedulerDidSendAccessibilityEvent(const facebook::react::ShadowView& shadowView, const std::string& eventType) = 0; 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 schedulerShouldMergeReactRevision(facebook::react::SurfaceId surfaceId) = 0; public virtual void schedulerShouldRenderTransactions(const std::shared_ptr& mountingCoordinator) = 0; @@ -5241,6 +5248,8 @@ class facebook::react::UIManagerCommitHook { class facebook::react::UIManagerDelegate { public using OnSurfaceStartCallback = std::function; + public virtual void uiManagerDidCaptureViewSnapshot(facebook::react::Tag tag, facebook::react::SurfaceId surfaceId) = 0; + public virtual void uiManagerDidClearPendingSnapshots() = 0; public virtual void uiManagerDidCreateShadowNode(const facebook::react::ShadowNode& shadowNode) = 0; public virtual void uiManagerDidDispatchCommand(const std::shared_ptr& shadowNode, const std::string& commandName, const folly::dynamic& args) = 0; public virtual void uiManagerDidFinishReactCommit(const facebook::react::ShadowTree& shadowTree) = 0; @@ -5248,6 +5257,7 @@ class facebook::react::UIManagerDelegate { public virtual void uiManagerDidPromoteReactRevision(const facebook::react::ShadowTree& shadowTree) = 0; public virtual void uiManagerDidSendAccessibilityEvent(const std::shared_ptr& shadowNode, const std::string& eventType) = 0; public virtual void uiManagerDidSetIsJSResponder(const std::shared_ptr& shadowNode, bool isJSResponder, bool blockNativeResponder) = 0; + 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 uiManagerShouldAddEventListener(std::shared_ptr listener) = 0; @@ -5275,8 +5285,10 @@ class facebook::react::UIManagerNativeAnimatedDelegateImpl : public facebook::re class facebook::react::UIManagerViewTransitionDelegate { public virtual std::optional getViewTransitionInstance(const std::string& name, const std::string& pseudo); + public virtual std::shared_ptr findPseudoElementShadowNodeByTag(facebook::react::Tag tag) const; public virtual void applyViewTransitionName(const facebook::react::ShadowNode& shadowNode, const std::string& name, const std::string& className); public virtual void cancelViewTransitionName(const facebook::react::ShadowNode& shadowNode, const std::string& name); + public virtual void createViewTransitionInstance(const std::string& name, facebook::react::Tag pseudoElementTag); public virtual void restoreViewTransitionName(const facebook::react::ShadowNode& shadowNode); public virtual void startViewTransition(std::function mutationCallback, std::function onReadyCallback, std::function onCompleteCallback); public virtual void startViewTransitionEnd(); @@ -5349,10 +5361,15 @@ class facebook::react::ViewShadowNodeProps : public facebook::react::HostPlatfor public ViewShadowNodeProps(const facebook::react::PropsParserContext& context, const facebook::react::ViewShadowNodeProps& sourceProps, const facebook::react::RawProps& rawProps); } -class facebook::react::ViewTransitionModule : public facebook::react::UIManagerViewTransitionDelegate { +class facebook::react::ViewTransitionModule : public facebook::react::UIManagerViewTransitionDelegate, public facebook::react::UIManagerCommitHook { + public virtual facebook::react::RootShadowNode::Unshared shadowTreeWillCommit(const facebook::react::ShadowTree& shadowTree, const facebook::react::RootShadowNode::Shared& oldRootShadowNode, const facebook::react::RootShadowNode::Unshared& newRootShadowNode, const facebook::react::ShadowTreeCommitOptions& commitOptions) noexcept override; public virtual std::optional getViewTransitionInstance(const std::string& name, const std::string& pseudo) override; + public virtual std::shared_ptr findPseudoElementShadowNodeByTag(facebook::react::Tag tag) const override; public virtual void applyViewTransitionName(const facebook::react::ShadowNode& shadowNode, const std::string& name, const std::string& className) override; public virtual void cancelViewTransitionName(const facebook::react::ShadowNode& shadowNode, const std::string& name) override; + public virtual void commitHookWasRegistered(const facebook::react::UIManager& uiManager) noexcept override; + public virtual void commitHookWasUnregistered(const facebook::react::UIManager& uiManager) noexcept override; + public virtual void createViewTransitionInstance(const std::string& name, facebook::react::Tag pseudoElementTag) override; public virtual void restoreViewTransitionName(const facebook::react::ShadowNode& shadowNode) override; public virtual void startViewTransition(std::function mutationCallback, std::function onReadyCallback, std::function onCompleteCallback) override; public virtual void startViewTransitionEnd() override; diff --git a/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api index c10403dd56f2..314ad5098fe1 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleDebugCxx.api @@ -7040,6 +7040,8 @@ class facebook::react::Scheduler : public facebook::react::UIManagerDelegate { public facebook::react::SchedulerDelegate* getDelegate() const; public std::shared_ptr getContextContainer() const; public std::shared_ptr getUIManager() const; + public virtual void uiManagerDidCaptureViewSnapshot(facebook::react::Tag tag, facebook::react::SurfaceId surfaceId) override; + public virtual void uiManagerDidClearPendingSnapshots() override; public virtual void uiManagerDidCreateShadowNode(const facebook::react::ShadowNode& shadowNode) override; public virtual void uiManagerDidDispatchCommand(const std::shared_ptr& shadowNode, const std::string& commandName, const folly::dynamic& args) override; public virtual void uiManagerDidFinishReactCommit(const facebook::react::ShadowTree& shadowTree) override; @@ -7047,6 +7049,7 @@ class facebook::react::Scheduler : public facebook::react::UIManagerDelegate { public virtual void uiManagerDidPromoteReactRevision(const facebook::react::ShadowTree& shadowTree) override; public virtual void uiManagerDidSendAccessibilityEvent(const std::shared_ptr& shadowNode, const std::string& eventType) override; public virtual void uiManagerDidSetIsJSResponder(const std::shared_ptr& shadowNode, bool isJSResponder, bool blockNativeResponder) override; + 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 uiManagerShouldAddEventListener(std::shared_ptr listener) final; @@ -7064,11 +7067,14 @@ class facebook::react::Scheduler : public facebook::react::UIManagerDelegate { } class facebook::react::SchedulerDelegate { + public virtual void schedulerDidCaptureViewSnapshot(facebook::react::Tag tag, facebook::react::SurfaceId surfaceId) = 0; + public virtual void schedulerDidClearPendingSnapshots() = 0; public virtual void schedulerDidDispatchCommand(const facebook::react::ShadowView& shadowView, const std::string& commandName, const folly::dynamic& args) = 0; public virtual void schedulerDidFinishTransaction(const std::shared_ptr& mountingCoordinator) = 0; public virtual void schedulerDidRequestPreliminaryViewAllocation(const facebook::react::ShadowNode& shadowNode) = 0; public virtual void schedulerDidSendAccessibilityEvent(const facebook::react::ShadowView& shadowView, const std::string& eventType) = 0; 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 schedulerShouldMergeReactRevision(facebook::react::SurfaceId surfaceId) = 0; public virtual void schedulerShouldRenderTransactions(const std::shared_ptr& mountingCoordinator) = 0; @@ -7820,6 +7826,8 @@ class facebook::react::UIManagerCommitHook { class facebook::react::UIManagerDelegate { public using OnSurfaceStartCallback = std::function; + public virtual void uiManagerDidCaptureViewSnapshot(facebook::react::Tag tag, facebook::react::SurfaceId surfaceId) = 0; + public virtual void uiManagerDidClearPendingSnapshots() = 0; public virtual void uiManagerDidCreateShadowNode(const facebook::react::ShadowNode& shadowNode) = 0; public virtual void uiManagerDidDispatchCommand(const std::shared_ptr& shadowNode, const std::string& commandName, const folly::dynamic& args) = 0; public virtual void uiManagerDidFinishReactCommit(const facebook::react::ShadowTree& shadowTree) = 0; @@ -7827,6 +7835,7 @@ class facebook::react::UIManagerDelegate { public virtual void uiManagerDidPromoteReactRevision(const facebook::react::ShadowTree& shadowTree) = 0; public virtual void uiManagerDidSendAccessibilityEvent(const std::shared_ptr& shadowNode, const std::string& eventType) = 0; public virtual void uiManagerDidSetIsJSResponder(const std::shared_ptr& shadowNode, bool isJSResponder, bool blockNativeResponder) = 0; + 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 uiManagerShouldAddEventListener(std::shared_ptr listener) = 0; @@ -7854,8 +7863,10 @@ class facebook::react::UIManagerNativeAnimatedDelegateImpl : public facebook::re class facebook::react::UIManagerViewTransitionDelegate { public virtual std::optional getViewTransitionInstance(const std::string& name, const std::string& pseudo); + public virtual std::shared_ptr findPseudoElementShadowNodeByTag(facebook::react::Tag tag) const; public virtual void applyViewTransitionName(const facebook::react::ShadowNode& shadowNode, const std::string& name, const std::string& className); public virtual void cancelViewTransitionName(const facebook::react::ShadowNode& shadowNode, const std::string& name); + public virtual void createViewTransitionInstance(const std::string& name, facebook::react::Tag pseudoElementTag); public virtual void restoreViewTransitionName(const facebook::react::ShadowNode& shadowNode); public virtual void startViewTransition(std::function mutationCallback, std::function onReadyCallback, std::function onCompleteCallback); public virtual void startViewTransitionEnd(); @@ -7925,10 +7936,15 @@ class facebook::react::ViewShadowNodeProps : public facebook::react::HostPlatfor public ViewShadowNodeProps(const facebook::react::PropsParserContext& context, const facebook::react::ViewShadowNodeProps& sourceProps, const facebook::react::RawProps& rawProps); } -class facebook::react::ViewTransitionModule : public facebook::react::UIManagerViewTransitionDelegate { +class facebook::react::ViewTransitionModule : public facebook::react::UIManagerViewTransitionDelegate, public facebook::react::UIManagerCommitHook { + public virtual facebook::react::RootShadowNode::Unshared shadowTreeWillCommit(const facebook::react::ShadowTree& shadowTree, const facebook::react::RootShadowNode::Shared& oldRootShadowNode, const facebook::react::RootShadowNode::Unshared& newRootShadowNode, const facebook::react::ShadowTreeCommitOptions& commitOptions) noexcept override; public virtual std::optional getViewTransitionInstance(const std::string& name, const std::string& pseudo) override; + public virtual std::shared_ptr findPseudoElementShadowNodeByTag(facebook::react::Tag tag) const override; public virtual void applyViewTransitionName(const facebook::react::ShadowNode& shadowNode, const std::string& name, const std::string& className) override; public virtual void cancelViewTransitionName(const facebook::react::ShadowNode& shadowNode, const std::string& name) override; + public virtual void commitHookWasRegistered(const facebook::react::UIManager& uiManager) noexcept override; + public virtual void commitHookWasUnregistered(const facebook::react::UIManager& uiManager) noexcept override; + public virtual void createViewTransitionInstance(const std::string& name, facebook::react::Tag pseudoElementTag) override; public virtual void restoreViewTransitionName(const facebook::react::ShadowNode& shadowNode) override; public virtual void startViewTransition(std::function mutationCallback, std::function onReadyCallback, std::function onCompleteCallback) override; public virtual void startViewTransitionEnd() override; diff --git a/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api b/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api index a9965274a91c..69fd72ccabf0 100644 --- a/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAppleReleaseCxx.api @@ -7037,6 +7037,8 @@ class facebook::react::Scheduler : public facebook::react::UIManagerDelegate { public facebook::react::SchedulerDelegate* getDelegate() const; public std::shared_ptr getContextContainer() const; public std::shared_ptr getUIManager() const; + public virtual void uiManagerDidCaptureViewSnapshot(facebook::react::Tag tag, facebook::react::SurfaceId surfaceId) override; + public virtual void uiManagerDidClearPendingSnapshots() override; public virtual void uiManagerDidCreateShadowNode(const facebook::react::ShadowNode& shadowNode) override; public virtual void uiManagerDidDispatchCommand(const std::shared_ptr& shadowNode, const std::string& commandName, const folly::dynamic& args) override; public virtual void uiManagerDidFinishReactCommit(const facebook::react::ShadowTree& shadowTree) override; @@ -7044,6 +7046,7 @@ class facebook::react::Scheduler : public facebook::react::UIManagerDelegate { public virtual void uiManagerDidPromoteReactRevision(const facebook::react::ShadowTree& shadowTree) override; public virtual void uiManagerDidSendAccessibilityEvent(const std::shared_ptr& shadowNode, const std::string& eventType) override; public virtual void uiManagerDidSetIsJSResponder(const std::shared_ptr& shadowNode, bool isJSResponder, bool blockNativeResponder) override; + 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 uiManagerShouldAddEventListener(std::shared_ptr listener) final; @@ -7061,11 +7064,14 @@ class facebook::react::Scheduler : public facebook::react::UIManagerDelegate { } class facebook::react::SchedulerDelegate { + public virtual void schedulerDidCaptureViewSnapshot(facebook::react::Tag tag, facebook::react::SurfaceId surfaceId) = 0; + public virtual void schedulerDidClearPendingSnapshots() = 0; public virtual void schedulerDidDispatchCommand(const facebook::react::ShadowView& shadowView, const std::string& commandName, const folly::dynamic& args) = 0; public virtual void schedulerDidFinishTransaction(const std::shared_ptr& mountingCoordinator) = 0; public virtual void schedulerDidRequestPreliminaryViewAllocation(const facebook::react::ShadowNode& shadowNode) = 0; public virtual void schedulerDidSendAccessibilityEvent(const facebook::react::ShadowView& shadowView, const std::string& eventType) = 0; 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 schedulerShouldMergeReactRevision(facebook::react::SurfaceId surfaceId) = 0; public virtual void schedulerShouldRenderTransactions(const std::shared_ptr& mountingCoordinator) = 0; @@ -7811,6 +7817,8 @@ class facebook::react::UIManagerCommitHook { class facebook::react::UIManagerDelegate { public using OnSurfaceStartCallback = std::function; + public virtual void uiManagerDidCaptureViewSnapshot(facebook::react::Tag tag, facebook::react::SurfaceId surfaceId) = 0; + public virtual void uiManagerDidClearPendingSnapshots() = 0; public virtual void uiManagerDidCreateShadowNode(const facebook::react::ShadowNode& shadowNode) = 0; public virtual void uiManagerDidDispatchCommand(const std::shared_ptr& shadowNode, const std::string& commandName, const folly::dynamic& args) = 0; public virtual void uiManagerDidFinishReactCommit(const facebook::react::ShadowTree& shadowTree) = 0; @@ -7818,6 +7826,7 @@ class facebook::react::UIManagerDelegate { public virtual void uiManagerDidPromoteReactRevision(const facebook::react::ShadowTree& shadowTree) = 0; public virtual void uiManagerDidSendAccessibilityEvent(const std::shared_ptr& shadowNode, const std::string& eventType) = 0; public virtual void uiManagerDidSetIsJSResponder(const std::shared_ptr& shadowNode, bool isJSResponder, bool blockNativeResponder) = 0; + 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 uiManagerShouldAddEventListener(std::shared_ptr listener) = 0; @@ -7845,8 +7854,10 @@ class facebook::react::UIManagerNativeAnimatedDelegateImpl : public facebook::re class facebook::react::UIManagerViewTransitionDelegate { public virtual std::optional getViewTransitionInstance(const std::string& name, const std::string& pseudo); + public virtual std::shared_ptr findPseudoElementShadowNodeByTag(facebook::react::Tag tag) const; public virtual void applyViewTransitionName(const facebook::react::ShadowNode& shadowNode, const std::string& name, const std::string& className); public virtual void cancelViewTransitionName(const facebook::react::ShadowNode& shadowNode, const std::string& name); + public virtual void createViewTransitionInstance(const std::string& name, facebook::react::Tag pseudoElementTag); public virtual void restoreViewTransitionName(const facebook::react::ShadowNode& shadowNode); public virtual void startViewTransition(std::function mutationCallback, std::function onReadyCallback, std::function onCompleteCallback); public virtual void startViewTransitionEnd(); @@ -7916,10 +7927,15 @@ class facebook::react::ViewShadowNodeProps : public facebook::react::HostPlatfor public ViewShadowNodeProps(const facebook::react::PropsParserContext& context, const facebook::react::ViewShadowNodeProps& sourceProps, const facebook::react::RawProps& rawProps); } -class facebook::react::ViewTransitionModule : public facebook::react::UIManagerViewTransitionDelegate { +class facebook::react::ViewTransitionModule : public facebook::react::UIManagerViewTransitionDelegate, public facebook::react::UIManagerCommitHook { + public virtual facebook::react::RootShadowNode::Unshared shadowTreeWillCommit(const facebook::react::ShadowTree& shadowTree, const facebook::react::RootShadowNode::Shared& oldRootShadowNode, const facebook::react::RootShadowNode::Unshared& newRootShadowNode, const facebook::react::ShadowTreeCommitOptions& commitOptions) noexcept override; public virtual std::optional getViewTransitionInstance(const std::string& name, const std::string& pseudo) override; + public virtual std::shared_ptr findPseudoElementShadowNodeByTag(facebook::react::Tag tag) const override; public virtual void applyViewTransitionName(const facebook::react::ShadowNode& shadowNode, const std::string& name, const std::string& className) override; public virtual void cancelViewTransitionName(const facebook::react::ShadowNode& shadowNode, const std::string& name) override; + public virtual void commitHookWasRegistered(const facebook::react::UIManager& uiManager) noexcept override; + public virtual void commitHookWasUnregistered(const facebook::react::UIManager& uiManager) noexcept override; + public virtual void createViewTransitionInstance(const std::string& name, facebook::react::Tag pseudoElementTag) override; public virtual void restoreViewTransitionName(const facebook::react::ShadowNode& shadowNode) override; public virtual void startViewTransition(std::function mutationCallback, std::function onReadyCallback, std::function onCompleteCallback) override; public virtual void startViewTransitionEnd() override; diff --git a/scripts/cxx-api/api-snapshots/ReactCommonDebugCxx.api b/scripts/cxx-api/api-snapshots/ReactCommonDebugCxx.api index 52daa8ae3342..db5b97440f2c 100644 --- a/scripts/cxx-api/api-snapshots/ReactCommonDebugCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactCommonDebugCxx.api @@ -3021,6 +3021,8 @@ class facebook::react::Scheduler : public facebook::react::UIManagerDelegate { public facebook::react::SchedulerDelegate* getDelegate() const; public std::shared_ptr getContextContainer() const; public std::shared_ptr getUIManager() const; + public virtual void uiManagerDidCaptureViewSnapshot(facebook::react::Tag tag, facebook::react::SurfaceId surfaceId) override; + public virtual void uiManagerDidClearPendingSnapshots() override; public virtual void uiManagerDidCreateShadowNode(const facebook::react::ShadowNode& shadowNode) override; public virtual void uiManagerDidDispatchCommand(const std::shared_ptr& shadowNode, const std::string& commandName, const folly::dynamic& args) override; public virtual void uiManagerDidFinishReactCommit(const facebook::react::ShadowTree& shadowTree) override; @@ -3028,6 +3030,7 @@ class facebook::react::Scheduler : public facebook::react::UIManagerDelegate { public virtual void uiManagerDidPromoteReactRevision(const facebook::react::ShadowTree& shadowTree) override; public virtual void uiManagerDidSendAccessibilityEvent(const std::shared_ptr& shadowNode, const std::string& eventType) override; public virtual void uiManagerDidSetIsJSResponder(const std::shared_ptr& shadowNode, bool isJSResponder, bool blockNativeResponder) override; + 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 uiManagerShouldAddEventListener(std::shared_ptr listener) final; @@ -3045,11 +3048,14 @@ class facebook::react::Scheduler : public facebook::react::UIManagerDelegate { } class facebook::react::SchedulerDelegate { + public virtual void schedulerDidCaptureViewSnapshot(facebook::react::Tag tag, facebook::react::SurfaceId surfaceId) = 0; + public virtual void schedulerDidClearPendingSnapshots() = 0; public virtual void schedulerDidDispatchCommand(const facebook::react::ShadowView& shadowView, const std::string& commandName, const folly::dynamic& args) = 0; public virtual void schedulerDidFinishTransaction(const std::shared_ptr& mountingCoordinator) = 0; public virtual void schedulerDidRequestPreliminaryViewAllocation(const facebook::react::ShadowNode& shadowNode) = 0; public virtual void schedulerDidSendAccessibilityEvent(const facebook::react::ShadowView& shadowView, const std::string& eventType) = 0; 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 schedulerShouldMergeReactRevision(facebook::react::SurfaceId surfaceId) = 0; public virtual void schedulerShouldRenderTransactions(const std::shared_ptr& mountingCoordinator) = 0; @@ -3717,6 +3723,8 @@ class facebook::react::UIManagerCommitHook { class facebook::react::UIManagerDelegate { public using OnSurfaceStartCallback = std::function; + public virtual void uiManagerDidCaptureViewSnapshot(facebook::react::Tag tag, facebook::react::SurfaceId surfaceId) = 0; + public virtual void uiManagerDidClearPendingSnapshots() = 0; public virtual void uiManagerDidCreateShadowNode(const facebook::react::ShadowNode& shadowNode) = 0; public virtual void uiManagerDidDispatchCommand(const std::shared_ptr& shadowNode, const std::string& commandName, const folly::dynamic& args) = 0; public virtual void uiManagerDidFinishReactCommit(const facebook::react::ShadowTree& shadowTree) = 0; @@ -3724,6 +3732,7 @@ class facebook::react::UIManagerDelegate { public virtual void uiManagerDidPromoteReactRevision(const facebook::react::ShadowTree& shadowTree) = 0; public virtual void uiManagerDidSendAccessibilityEvent(const std::shared_ptr& shadowNode, const std::string& eventType) = 0; public virtual void uiManagerDidSetIsJSResponder(const std::shared_ptr& shadowNode, bool isJSResponder, bool blockNativeResponder) = 0; + 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 uiManagerShouldAddEventListener(std::shared_ptr listener) = 0; @@ -3751,8 +3760,10 @@ class facebook::react::UIManagerNativeAnimatedDelegateImpl : public facebook::re class facebook::react::UIManagerViewTransitionDelegate { public virtual std::optional getViewTransitionInstance(const std::string& name, const std::string& pseudo); + public virtual std::shared_ptr findPseudoElementShadowNodeByTag(facebook::react::Tag tag) const; public virtual void applyViewTransitionName(const facebook::react::ShadowNode& shadowNode, const std::string& name, const std::string& className); public virtual void cancelViewTransitionName(const facebook::react::ShadowNode& shadowNode, const std::string& name); + public virtual void createViewTransitionInstance(const std::string& name, facebook::react::Tag pseudoElementTag); public virtual void restoreViewTransitionName(const facebook::react::ShadowNode& shadowNode); public virtual void startViewTransition(std::function mutationCallback, std::function onReadyCallback, std::function onCompleteCallback); public virtual void startViewTransitionEnd(); @@ -3813,10 +3824,15 @@ class facebook::react::ViewShadowNodeProps : public facebook::react::HostPlatfor public ViewShadowNodeProps(const facebook::react::PropsParserContext& context, const facebook::react::ViewShadowNodeProps& sourceProps, const facebook::react::RawProps& rawProps); } -class facebook::react::ViewTransitionModule : public facebook::react::UIManagerViewTransitionDelegate { +class facebook::react::ViewTransitionModule : public facebook::react::UIManagerViewTransitionDelegate, public facebook::react::UIManagerCommitHook { + public virtual facebook::react::RootShadowNode::Unshared shadowTreeWillCommit(const facebook::react::ShadowTree& shadowTree, const facebook::react::RootShadowNode::Shared& oldRootShadowNode, const facebook::react::RootShadowNode::Unshared& newRootShadowNode, const facebook::react::ShadowTreeCommitOptions& commitOptions) noexcept override; public virtual std::optional getViewTransitionInstance(const std::string& name, const std::string& pseudo) override; + public virtual std::shared_ptr findPseudoElementShadowNodeByTag(facebook::react::Tag tag) const override; public virtual void applyViewTransitionName(const facebook::react::ShadowNode& shadowNode, const std::string& name, const std::string& className) override; public virtual void cancelViewTransitionName(const facebook::react::ShadowNode& shadowNode, const std::string& name) override; + public virtual void commitHookWasRegistered(const facebook::react::UIManager& uiManager) noexcept override; + public virtual void commitHookWasUnregistered(const facebook::react::UIManager& uiManager) noexcept override; + public virtual void createViewTransitionInstance(const std::string& name, facebook::react::Tag pseudoElementTag) override; public virtual void restoreViewTransitionName(const facebook::react::ShadowNode& shadowNode) override; public virtual void startViewTransition(std::function mutationCallback, std::function onReadyCallback, std::function onCompleteCallback) override; public virtual void startViewTransitionEnd() override; diff --git a/scripts/cxx-api/api-snapshots/ReactCommonReleaseCxx.api b/scripts/cxx-api/api-snapshots/ReactCommonReleaseCxx.api index 85bf37ad00bd..f35367f460b8 100644 --- a/scripts/cxx-api/api-snapshots/ReactCommonReleaseCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactCommonReleaseCxx.api @@ -3018,6 +3018,8 @@ class facebook::react::Scheduler : public facebook::react::UIManagerDelegate { public facebook::react::SchedulerDelegate* getDelegate() const; public std::shared_ptr getContextContainer() const; public std::shared_ptr getUIManager() const; + public virtual void uiManagerDidCaptureViewSnapshot(facebook::react::Tag tag, facebook::react::SurfaceId surfaceId) override; + public virtual void uiManagerDidClearPendingSnapshots() override; public virtual void uiManagerDidCreateShadowNode(const facebook::react::ShadowNode& shadowNode) override; public virtual void uiManagerDidDispatchCommand(const std::shared_ptr& shadowNode, const std::string& commandName, const folly::dynamic& args) override; public virtual void uiManagerDidFinishReactCommit(const facebook::react::ShadowTree& shadowTree) override; @@ -3025,6 +3027,7 @@ class facebook::react::Scheduler : public facebook::react::UIManagerDelegate { public virtual void uiManagerDidPromoteReactRevision(const facebook::react::ShadowTree& shadowTree) override; public virtual void uiManagerDidSendAccessibilityEvent(const std::shared_ptr& shadowNode, const std::string& eventType) override; public virtual void uiManagerDidSetIsJSResponder(const std::shared_ptr& shadowNode, bool isJSResponder, bool blockNativeResponder) override; + 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 uiManagerShouldAddEventListener(std::shared_ptr listener) final; @@ -3042,11 +3045,14 @@ class facebook::react::Scheduler : public facebook::react::UIManagerDelegate { } class facebook::react::SchedulerDelegate { + public virtual void schedulerDidCaptureViewSnapshot(facebook::react::Tag tag, facebook::react::SurfaceId surfaceId) = 0; + public virtual void schedulerDidClearPendingSnapshots() = 0; public virtual void schedulerDidDispatchCommand(const facebook::react::ShadowView& shadowView, const std::string& commandName, const folly::dynamic& args) = 0; public virtual void schedulerDidFinishTransaction(const std::shared_ptr& mountingCoordinator) = 0; public virtual void schedulerDidRequestPreliminaryViewAllocation(const facebook::react::ShadowNode& shadowNode) = 0; public virtual void schedulerDidSendAccessibilityEvent(const facebook::react::ShadowView& shadowView, const std::string& eventType) = 0; 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 schedulerShouldMergeReactRevision(facebook::react::SurfaceId surfaceId) = 0; public virtual void schedulerShouldRenderTransactions(const std::shared_ptr& mountingCoordinator) = 0; @@ -3708,6 +3714,8 @@ class facebook::react::UIManagerCommitHook { class facebook::react::UIManagerDelegate { public using OnSurfaceStartCallback = std::function; + public virtual void uiManagerDidCaptureViewSnapshot(facebook::react::Tag tag, facebook::react::SurfaceId surfaceId) = 0; + public virtual void uiManagerDidClearPendingSnapshots() = 0; public virtual void uiManagerDidCreateShadowNode(const facebook::react::ShadowNode& shadowNode) = 0; public virtual void uiManagerDidDispatchCommand(const std::shared_ptr& shadowNode, const std::string& commandName, const folly::dynamic& args) = 0; public virtual void uiManagerDidFinishReactCommit(const facebook::react::ShadowTree& shadowTree) = 0; @@ -3715,6 +3723,7 @@ class facebook::react::UIManagerDelegate { public virtual void uiManagerDidPromoteReactRevision(const facebook::react::ShadowTree& shadowTree) = 0; public virtual void uiManagerDidSendAccessibilityEvent(const std::shared_ptr& shadowNode, const std::string& eventType) = 0; public virtual void uiManagerDidSetIsJSResponder(const std::shared_ptr& shadowNode, bool isJSResponder, bool blockNativeResponder) = 0; + 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 uiManagerShouldAddEventListener(std::shared_ptr listener) = 0; @@ -3742,8 +3751,10 @@ class facebook::react::UIManagerNativeAnimatedDelegateImpl : public facebook::re class facebook::react::UIManagerViewTransitionDelegate { public virtual std::optional getViewTransitionInstance(const std::string& name, const std::string& pseudo); + public virtual std::shared_ptr findPseudoElementShadowNodeByTag(facebook::react::Tag tag) const; public virtual void applyViewTransitionName(const facebook::react::ShadowNode& shadowNode, const std::string& name, const std::string& className); public virtual void cancelViewTransitionName(const facebook::react::ShadowNode& shadowNode, const std::string& name); + public virtual void createViewTransitionInstance(const std::string& name, facebook::react::Tag pseudoElementTag); public virtual void restoreViewTransitionName(const facebook::react::ShadowNode& shadowNode); public virtual void startViewTransition(std::function mutationCallback, std::function onReadyCallback, std::function onCompleteCallback); public virtual void startViewTransitionEnd(); @@ -3804,10 +3815,15 @@ class facebook::react::ViewShadowNodeProps : public facebook::react::HostPlatfor public ViewShadowNodeProps(const facebook::react::PropsParserContext& context, const facebook::react::ViewShadowNodeProps& sourceProps, const facebook::react::RawProps& rawProps); } -class facebook::react::ViewTransitionModule : public facebook::react::UIManagerViewTransitionDelegate { +class facebook::react::ViewTransitionModule : public facebook::react::UIManagerViewTransitionDelegate, public facebook::react::UIManagerCommitHook { + public virtual facebook::react::RootShadowNode::Unshared shadowTreeWillCommit(const facebook::react::ShadowTree& shadowTree, const facebook::react::RootShadowNode::Shared& oldRootShadowNode, const facebook::react::RootShadowNode::Unshared& newRootShadowNode, const facebook::react::ShadowTreeCommitOptions& commitOptions) noexcept override; public virtual std::optional getViewTransitionInstance(const std::string& name, const std::string& pseudo) override; + public virtual std::shared_ptr findPseudoElementShadowNodeByTag(facebook::react::Tag tag) const override; public virtual void applyViewTransitionName(const facebook::react::ShadowNode& shadowNode, const std::string& name, const std::string& className) override; public virtual void cancelViewTransitionName(const facebook::react::ShadowNode& shadowNode, const std::string& name) override; + public virtual void commitHookWasRegistered(const facebook::react::UIManager& uiManager) noexcept override; + public virtual void commitHookWasUnregistered(const facebook::react::UIManager& uiManager) noexcept override; + public virtual void createViewTransitionInstance(const std::string& name, facebook::react::Tag pseudoElementTag) override; public virtual void restoreViewTransitionName(const facebook::react::ShadowNode& shadowNode) override; public virtual void startViewTransition(std::function mutationCallback, std::function onReadyCallback, std::function onCompleteCallback) override; public virtual void startViewTransitionEnd() override;