From e61bbd03f99c840324af6dc2808b163d36f49318 Mon Sep 17 00:00:00 2001 From: Bartlomiej Bloniarz Date: Thu, 20 Nov 2025 04:00:02 -0800 Subject: [PATCH 1/2] Extract cloneProp in animation backend (#54606) Summary: This diff extracts the `cloneProp` helper from `AnimationBackend::cloneProps` so the logic can be reused # Changelog [General] [Changed] - Extracted `cloneProp` from `AnimationBackend.cpp` to `AnimatedProps.h` Differential Revision: D86414627 --- .../renderer/animationbackend/AnimatedProps.h | 29 +++++++++++++++++++ .../animationbackend/AnimationBackend.cpp | 29 +------------------ 2 files changed, 30 insertions(+), 28 deletions(-) diff --git a/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimatedProps.h b/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimatedProps.h index d65411a812c6d7..25e69ba6fd0051 100644 --- a/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimatedProps.h +++ b/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimatedProps.h @@ -37,4 +37,33 @@ struct AnimatedProps { std::vector> props; std::unique_ptr rawProps; }; + +inline void cloneProp(BaseViewProps &viewProps, std::unique_ptr &animatedProp) +{ + switch (animatedProp->propName) { + case OPACITY: + viewProps.opacity = get(animatedProp); + break; + + case WIDTH: + viewProps.yogaStyle.setDimension(yoga::Dimension::Width, get(animatedProp)); + break; + + case HEIGHT: + viewProps.yogaStyle.setDimension(yoga::Dimension::Height, get(animatedProp)); + break; + + case BORDER_RADII: + viewProps.borderRadii = get(animatedProp); + break; + + case FLEX: + viewProps.yogaStyle.setFlex(get(animatedProp)); + break; + + case TRANSFORM: + viewProps.transform = get(animatedProp); + break; + } +} } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimationBackend.cpp b/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimationBackend.cpp index 6b49decc8cf2be..24fcd3996cc8d5 100644 --- a/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimationBackend.cpp +++ b/packages/react-native/ReactCommon/react/renderer/animationbackend/AnimationBackend.cpp @@ -41,34 +41,7 @@ static inline Props::Shared cloneProps( auto viewProps = std::const_pointer_cast( std::static_pointer_cast(newProps)); for (auto& animatedProp : animatedProps.props) { - switch (animatedProp->propName) { - case OPACITY: - viewProps->opacity = get(animatedProp); - break; - - case WIDTH: - viewProps->yogaStyle.setDimension( - yoga::Dimension::Width, get(animatedProp)); - break; - - case HEIGHT: - viewProps->yogaStyle.setDimension( - yoga::Dimension::Height, - get(animatedProp)); - break; - - case BORDER_RADII: - viewProps->borderRadii = get(animatedProp); - break; - - case FLEX: - viewProps->yogaStyle.setFlex(get(animatedProp)); - break; - - case TRANSFORM: - viewProps->transform = get(animatedProp); - break; - } + cloneProp(*viewProps, animatedProp); } return newProps; } From 9b6bb18fac450aab5154780cf9baf5d1f0322342 Mon Sep 17 00:00:00 2001 From: Bartlomiej Bloniarz Date: Thu, 20 Nov 2025 04:00:02 -0800 Subject: [PATCH 2/2] Pass families to Native Animated Summary: This PR allows C++ Native Animated to use `ShadowNodeFamily` instances to use the `cloneMultiple` method when pushing updates through the `ShadowTree` in `AnimationBackend` # Changelog [General] [Added] - Add `connectAnimatedNodeToShadowNodeFamily` method to `NativeAnimatedModule` and `NativeAnimatedTurboModule` Differential Revision: D84055752 --- .../__tests__/AnimatedBackend-itest.js | 54 ++++++++++++++++ .../Libraries/Animated/nodes/AnimatedProps.js | 20 ++++++ .../RCTNativeAnimatedTurboModule.mm | 2 + .../ReactAndroid/api/ReactAndroid.api | 1 + .../react/animated/NativeAnimatedModule.kt | 2 + .../renderer/animated/AnimatedModule.cpp | 19 ++++++ .../react/renderer/animated/AnimatedModule.h | 8 +++ .../animated/NativeAnimatedNodesManager.cpp | 63 +++++++++++++++++-- .../animated/NativeAnimatedNodesManager.h | 7 ++- .../animated/nodes/PropsAnimatedNode.cpp | 11 +++- .../animated/nodes/PropsAnimatedNode.h | 3 + .../private/animated/NativeAnimatedHelper.js | 12 ++++ .../modules/NativeAnimatedModule.js | 4 ++ .../modules/NativeAnimatedTurboModule.js | 4 ++ 14 files changed, 204 insertions(+), 6 deletions(-) diff --git a/packages/react-native/Libraries/Animated/__tests__/AnimatedBackend-itest.js b/packages/react-native/Libraries/Animated/__tests__/AnimatedBackend-itest.js index ae7e2f61ca8423..990d086faf8600 100644 --- a/packages/react-native/Libraries/Animated/__tests__/AnimatedBackend-itest.js +++ b/packages/react-native/Libraries/Animated/__tests__/AnimatedBackend-itest.js @@ -17,6 +17,7 @@ import ensureInstance from '../../../src/private/__tests__/utilities/ensureInsta import * as Fantom from '@react-native/fantom'; import {createRef} from 'react'; import {Animated, useAnimatedValue} from 'react-native'; +import {allowStyleProp} from 'react-native/Libraries/Animated/NativeAnimatedAllowlist'; import ReactNativeElement from 'react-native/src/private/webapis/dom/nodes/ReactNativeElement'; test('animated opacity', () => { @@ -73,3 +74,56 @@ test('animated opacity', () => { , ); }); + +test('animate layout props', () => { + const viewRef = createRef(); + allowStyleProp('height'); + + let _animatedHeight; + let _heightAnimation; + + function MyApp() { + const animatedHeight = useAnimatedValue(0); + _animatedHeight = animatedHeight; + return ( + + ); + } + + const root = Fantom.createRoot(); + + Fantom.runTask(() => { + root.render(); + }); + + const viewElement = ensureInstance(viewRef.current, ReactNativeElement); + + Fantom.runTask(() => { + _heightAnimation = Animated.timing(_animatedHeight, { + toValue: 100, + duration: 10, + useNativeDriver: true, + }).start(); + }); + + Fantom.unstable_produceFramesForDuration(10); + + // TODO: this shouldn't be neccessary since animation should be stopped after duration + Fantom.runTask(() => { + _heightAnimation?.stop(); + }); + + // TODO: getFabricUpdateProps is not working with the cloneMutliple method + // expect(Fantom.unstable_getFabricUpdateProps(viewElement).height).toBe(100); + expect(root.getRenderedOutput({props: ['height']}).toJSX()).toEqual( + , + ); +}); diff --git a/packages/react-native/Libraries/Animated/nodes/AnimatedProps.js b/packages/react-native/Libraries/Animated/nodes/AnimatedProps.js index af89f0d9ba21a1..6ecc3ccb76c77e 100644 --- a/packages/react-native/Libraries/Animated/nodes/AnimatedProps.js +++ b/packages/react-native/Libraries/Animated/nodes/AnimatedProps.js @@ -14,6 +14,7 @@ import type {AnimatedStyleAllowlist} from './AnimatedStyle'; import NativeAnimatedHelper from '../../../src/private/animated/NativeAnimatedHelper'; import {findNodeHandle} from '../../ReactNative/RendererProxy'; +import {getNodeFromPublicInstance} from '../../ReactPrivate/ReactNativePrivateInterface'; import flattenStyle from '../../StyleSheet/flattenStyle'; import {AnimatedEvent} from '../AnimatedEvent'; import AnimatedNode from './AnimatedNode'; @@ -249,6 +250,9 @@ export default class AnimatedProps extends AnimatedNode { if (this._target != null) { this.#connectAnimatedView(this._target); } + if (this._target != null) { + this.#connectShadowNode(this._target); + } } } @@ -259,6 +263,9 @@ export default class AnimatedProps extends AnimatedNode { this._target = {instance, connectedViewTag: null}; if (this.__isNative) { this.#connectAnimatedView(this._target); + if (this._target) { + this.#connectShadowNode(this._target); + } } } @@ -279,6 +286,19 @@ export default class AnimatedProps extends AnimatedNode { target.connectedViewTag = viewTag; } + #connectShadowNode(target: TargetView): void { + invariant(this.__isNative, 'Expected node to be marked as "native"'); + // $FlowExpectedError[incompatible-type] - target.instance may be an HTMLElement but we need ReactNativeElement for Fabric + const shadowNode = getNodeFromPublicInstance(target.instance); + if (shadowNode == null) { + return; + } + NativeAnimatedHelper.API.connectAnimatedNodeToShadowNodeFamily( + this.__getNativeTag(), + shadowNode, + ); + } + #disconnectAnimatedView(target: TargetView): void { invariant(this.__isNative, 'Expected node to be marked as "native"'); const viewTag = target.connectedViewTag; diff --git a/packages/react-native/Libraries/NativeAnimation/RCTNativeAnimatedTurboModule.mm b/packages/react-native/Libraries/NativeAnimation/RCTNativeAnimatedTurboModule.mm index a168bddff83abb..7429b1b92eac48 100644 --- a/packages/react-native/Libraries/NativeAnimation/RCTNativeAnimatedTurboModule.mm +++ b/packages/react-native/Libraries/NativeAnimation/RCTNativeAnimatedTurboModule.mm @@ -165,6 +165,8 @@ - (void)setSurfacePresenter:(id)surfacePresenter }]; } +RCT_EXPORT_METHOD(connectAnimatedNodeToShadowNodeFamily : (double)nodeTag shadowNode : (NSDictionary *)shadowNode) {} + RCT_EXPORT_METHOD(disconnectAnimatedNodeFromView : (double)nodeTag viewTag : (double)viewTag) { [self queueOperationBlock:^(RCTNativeAnimatedNodesManager *nodesManager) { diff --git a/packages/react-native/ReactAndroid/api/ReactAndroid.api b/packages/react-native/ReactAndroid/api/ReactAndroid.api index c39a442b5f7d19..2fb63f4ae4b221 100644 --- a/packages/react-native/ReactAndroid/api/ReactAndroid.api +++ b/packages/react-native/ReactAndroid/api/ReactAndroid.api @@ -457,6 +457,7 @@ public final class com/facebook/react/animated/NativeAnimatedModule : com/facebo public fun (Lcom/facebook/react/bridge/ReactApplicationContext;)V public fun addAnimatedEventToView (DLjava/lang/String;Lcom/facebook/react/bridge/ReadableMap;)V public fun addListener (Ljava/lang/String;)V + public fun connectAnimatedNodeToShadowNodeFamily (DLcom/facebook/react/bridge/ReadableMap;)V public fun connectAnimatedNodeToView (DD)V public fun connectAnimatedNodes (DD)V public fun createAnimatedNode (DLcom/facebook/react/bridge/ReadableMap;)V diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.kt index 6c5a505c9218e2..ca4a4babb3f4b8 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/animated/NativeAnimatedModule.kt @@ -1117,4 +1117,6 @@ public class NativeAnimatedModule(reactContext: ReactApplicationContext) : public const val ANIMATED_MODULE_DEBUG: Boolean = false } + + override fun connectAnimatedNodeToShadowNodeFamily(p0: Double, p1: ReadableMap) {} } diff --git a/packages/react-native/ReactCommon/react/renderer/animated/AnimatedModule.cpp b/packages/react-native/ReactCommon/react/renderer/animated/AnimatedModule.cpp index 8a8b8edc79d285..f3bd8fae4dab02 100644 --- a/packages/react-native/ReactCommon/react/renderer/animated/AnimatedModule.cpp +++ b/packages/react-native/ReactCommon/react/renderer/animated/AnimatedModule.cpp @@ -160,6 +160,20 @@ void AnimatedModule::connectAnimatedNodeToView( ConnectAnimatedNodeToViewOp{.nodeTag = nodeTag, .viewTag = viewTag}); } +void AnimatedModule::connectAnimatedNodeToShadowNodeFamily( + jsi::Runtime& rt, + Tag nodeTag, + jsi::Object shadowNodeObj) { + const auto& nativeState = shadowNodeObj.getNativeState(rt); + const auto& shadowNode = + std::dynamic_pointer_cast(nativeState)->shadowNode; + + operations_.emplace_back( + ConnectAnimatedNodeToShadowNodeFamilyOp{ + .nodeTag = nodeTag, + .shadowNodeFamily = shadowNode->getFamilyShared()}); +} + void AnimatedModule::disconnectAnimatedNodeFromView( jsi::Runtime& /*rt*/, Tag nodeTag, @@ -282,6 +296,11 @@ void AnimatedModule::executeOperation( DisconnectAnimatedNodeFromViewOp>) { nodesManager->disconnectAnimatedNodeFromView( op.nodeTag, op.viewTag); + } else if constexpr (std::is_same_v< + T, + ConnectAnimatedNodeToShadowNodeFamilyOp>) { + nodesManager->connectAnimatedNodeToShadowNodeFamily( + op.nodeTag, op.shadowNodeFamily); } else if constexpr (std::is_same_v) { nodesManager->restoreDefaultValues(op.nodeTag); } else if constexpr (std::is_same_v) { diff --git a/packages/react-native/ReactCommon/react/renderer/animated/AnimatedModule.h b/packages/react-native/ReactCommon/react/renderer/animated/AnimatedModule.h index a54254e6a6b7c6..858cd95e1b4695 100644 --- a/packages/react-native/ReactCommon/react/renderer/animated/AnimatedModule.h +++ b/packages/react-native/ReactCommon/react/renderer/animated/AnimatedModule.h @@ -87,6 +87,11 @@ class AnimatedModule : public NativeAnimatedModuleCxxSpec, publi Tag viewTag{}; }; + struct ConnectAnimatedNodeToShadowNodeFamilyOp { + Tag nodeTag{}; + std::shared_ptr shadowNodeFamily{}; + }; + struct DisconnectAnimatedNodeFromViewOp { Tag nodeTag{}; Tag viewTag{}; @@ -124,6 +129,7 @@ class AnimatedModule : public NativeAnimatedModuleCxxSpec, publi SetAnimatedNodeOffsetOp, SetAnimatedNodeValueOp, ConnectAnimatedNodeToViewOp, + ConnectAnimatedNodeToShadowNodeFamilyOp, DisconnectAnimatedNodeFromViewOp, RestoreDefaultValuesOp, FlattenAnimatedNodeOffsetOp, @@ -176,6 +182,8 @@ class AnimatedModule : public NativeAnimatedModuleCxxSpec, publi void connectAnimatedNodeToView(jsi::Runtime &rt, Tag nodeTag, Tag viewTag); + void connectAnimatedNodeToShadowNodeFamily(jsi::Runtime &rt, Tag nodeTag, jsi::Object shadowNode); + void disconnectAnimatedNodeFromView(jsi::Runtime &rt, Tag nodeTag, Tag viewTag); void restoreDefaultValues(jsi::Runtime &rt, Tag nodeTag); diff --git a/packages/react-native/ReactCommon/react/renderer/animated/NativeAnimatedNodesManager.cpp b/packages/react-native/ReactCommon/react/renderer/animated/NativeAnimatedNodesManager.cpp index 50482192a50a2c..76978232e99f8c 100644 --- a/packages/react-native/ReactCommon/react/renderer/animated/NativeAnimatedNodesManager.cpp +++ b/packages/react-native/ReactCommon/react/renderer/animated/NativeAnimatedNodesManager.cpp @@ -238,6 +238,20 @@ void NativeAnimatedNodesManager::connectAnimatedNodeToView( } } +void NativeAnimatedNodesManager::connectAnimatedNodeToShadowNodeFamily( + Tag propsNodeTag, + std::shared_ptr family) noexcept { + react_native_assert(propsNodeTag); + auto node = getAnimatedNode(propsNodeTag); + if (node != nullptr) { + node->connectToFamily(family); + updatedNodeTags_.insert(node->tag()); + } else { + LOG(WARNING) + << "Cannot ConnectAnimatedNodeToShadowNodeFamily, animated node has to be props type"; + } +} + void NativeAnimatedNodesManager::disconnectAnimatedNodeFromView( Tag propsNodeTag, Tag viewTag) noexcept { @@ -889,10 +903,14 @@ void NativeAnimatedNodesManager::schedulePropsCommit( Tag viewTag, const folly::dynamic& props, bool layoutStyleUpdated, - bool forceFabricCommit) noexcept { + bool forceFabricCommit, + std::shared_ptr family) noexcept { if (ReactNativeFeatureFlags::useSharedAnimatedBackend()) { if (layoutStyleUpdated) { mergeObjects(updateViewProps_[viewTag], props); + if (family) { + tagToShadowNodeFamily_[viewTag] = std::move(family); + } } else { mergeObjects(updateViewPropsDirect_[viewTag], props); } @@ -1003,7 +1021,31 @@ AnimationMutations NativeAnimatedNodesManager::pullAnimationMutations() { AnimationMutation{tag, nullptr, propsBuilder.get()}); containsChange = true; } - updateViewPropsDirect_.clear(); + for (auto& [tag, props] : updateViewProps_) { + auto familyIt = tagToShadowNodeFamily_.find(tag); + if (familyIt != tagToShadowNodeFamily_.end()) { + if (props.find("width") != props.items().end()) { + propsBuilder.setWidth( + yoga::Style::SizeLength::points(props["width"].asDouble())); + } + if (props.find("height") != props.items().end()) { + propsBuilder.setHeight( + yoga::Style::SizeLength::points(props["height"].asDouble())); + } + // propsBuilder.storeDynamic(props); + mutations.push_back( + AnimationMutation{ + .tag = tag, + .family = familyIt->second.get(), + .props = propsBuilder.get()}); + } + containsChange = true; + } + if (containsChange) { + updateViewPropsDirect_.clear(); + updateViewProps_.clear(); + tagToShadowNodeFamily_.clear(); + } } if (!containsChange) { @@ -1023,7 +1065,8 @@ AnimationMutations NativeAnimatedNodesManager::pullAnimationMutations() { } } - // Step 2: update all nodes that are connected to the finished animations. + // Step 2: update all nodes that are connected to the finished + // animations. updateNodes(finishedAnimationValueNodes); isEventAnimationInProgress_ = false; @@ -1034,6 +1077,17 @@ AnimationMutations NativeAnimatedNodesManager::pullAnimationMutations() { mutations.push_back( AnimationMutation{tag, nullptr, propsBuilder.get()}); } + for (auto& [tag, props] : updateViewProps_) { + auto familyIt = tagToShadowNodeFamily_.find(tag); + if (familyIt != tagToShadowNodeFamily_.end()) { + propsBuilder.storeDynamic(props); + mutations.push_back( + AnimationMutation{ + .tag = tag, + .family = familyIt->second.get(), + .props = propsBuilder.get()}); + } + } } } else { // There is no active animation. Stop the render callback. @@ -1113,7 +1167,8 @@ void NativeAnimatedNodesManager::onRender() { } } - // Step 2: update all nodes that are connected to the finished animations. + // Step 2: update all nodes that are connected to the finished + // animations. updateNodes(finishedAnimationValueNodes); isEventAnimationInProgress_ = false; diff --git a/packages/react-native/ReactCommon/react/renderer/animated/NativeAnimatedNodesManager.h b/packages/react-native/ReactCommon/react/renderer/animated/NativeAnimatedNodesManager.h index 965f29489fdfc8..2ea9695e66e933 100644 --- a/packages/react-native/ReactCommon/react/renderer/animated/NativeAnimatedNodesManager.h +++ b/packages/react-native/ReactCommon/react/renderer/animated/NativeAnimatedNodesManager.h @@ -21,6 +21,7 @@ #include #endif #include +#include #include #include #include @@ -95,6 +96,8 @@ class NativeAnimatedNodesManager { void connectAnimatedNodeToView(Tag propsNodeTag, Tag viewTag) noexcept; + void connectAnimatedNodeToShadowNodeFamily(Tag propsNodeTag, std::shared_ptr family) noexcept; + void disconnectAnimatedNodes(Tag parentTag, Tag childTag) noexcept; void disconnectAnimatedNodeFromView(Tag propsNodeTag, Tag viewTag) noexcept; @@ -144,7 +147,8 @@ class NativeAnimatedNodesManager { Tag viewTag, const folly::dynamic &props, bool layoutStyleUpdated, - bool forceFabricCommit) noexcept; + bool forceFabricCommit, + std::shared_ptr family = nullptr) noexcept; /** * Commits all pending animated property updates to their respective views. @@ -251,6 +255,7 @@ class NativeAnimatedNodesManager { std::unordered_map updateViewProps_{}; std::unordered_map updateViewPropsDirect_{}; + std::unordered_map> tagToShadowNodeFamily_{}; /* * Sometimes a view is not longer connected to a PropsAnimatedNode, but diff --git a/packages/react-native/ReactCommon/react/renderer/animated/nodes/PropsAnimatedNode.cpp b/packages/react-native/ReactCommon/react/renderer/animated/nodes/PropsAnimatedNode.cpp index 8303b74741b898..b343197f55d3f0 100644 --- a/packages/react-native/ReactCommon/react/renderer/animated/nodes/PropsAnimatedNode.cpp +++ b/packages/react-native/ReactCommon/react/renderer/animated/nodes/PropsAnimatedNode.cpp @@ -58,6 +58,11 @@ void PropsAnimatedNode::connectToView(Tag viewTag) { connectedViewTag_ = viewTag; } +void PropsAnimatedNode::connectToFamily( + std::shared_ptr& family) { + viewShadowNodeFamily_ = family; +} + void PropsAnimatedNode::disconnectFromView(Tag viewTag) { react_native_assert( connectedViewTag_ == viewTag && @@ -144,7 +149,11 @@ void PropsAnimatedNode::update(bool forceFabricCommit) { layoutStyleUpdated_ = isLayoutStyleUpdated(getConfig()["props"], *manager_); manager_->schedulePropsCommit( - connectedViewTag_, props_, layoutStyleUpdated_, forceFabricCommit); + connectedViewTag_, + props_, + layoutStyleUpdated_, + forceFabricCommit, + viewShadowNodeFamily_.lock()); } } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/animated/nodes/PropsAnimatedNode.h b/packages/react-native/ReactCommon/react/renderer/animated/nodes/PropsAnimatedNode.h index 9d654a33b8e11c..5182785b98dc58 100644 --- a/packages/react-native/ReactCommon/react/renderer/animated/nodes/PropsAnimatedNode.h +++ b/packages/react-native/ReactCommon/react/renderer/animated/nodes/PropsAnimatedNode.h @@ -14,6 +14,7 @@ #include "AnimatedNode.h" #include +#include #include namespace facebook::react { @@ -21,6 +22,7 @@ class PropsAnimatedNode final : public AnimatedNode { public: PropsAnimatedNode(Tag tag, const folly::dynamic &config, NativeAnimatedNodesManager &manager); void connectToView(Tag viewTag); + void connectToFamily(std::shared_ptr &family); void disconnectFromView(Tag viewTag); void restoreDefaultValues(); @@ -45,5 +47,6 @@ class PropsAnimatedNode final : public AnimatedNode { bool layoutStyleUpdated_{false}; Tag connectedViewTag_{animated::undefinedAnimatedNodeIdentifier}; + std::weak_ptr viewShadowNodeFamily_{}; }; } // namespace facebook::react diff --git a/packages/react-native/src/private/animated/NativeAnimatedHelper.js b/packages/react-native/src/private/animated/NativeAnimatedHelper.js index 5cde2ceef75da7..fb3027e621d917 100644 --- a/packages/react-native/src/private/animated/NativeAnimatedHelper.js +++ b/packages/react-native/src/private/animated/NativeAnimatedHelper.js @@ -27,6 +27,7 @@ import Platform from '../../../Libraries/Utilities/Platform'; import * as ReactNativeFeatureFlags from '../featureflags/ReactNativeFeatureFlags'; import invariant from 'invariant'; import nullthrows from 'nullthrows'; +import type {Node} from '../../../Libraries/Renderer/shims/ReactNativeTypes'; // TODO T69437152 @petetheheat - Delete this fork when Fabric ships to 100%. const NativeAnimatedModule: typeof NativeAnimatedTurboModule = @@ -83,6 +84,7 @@ function createNativeOperations(): $NonMaybeType { 'removeAnimatedEventFromView', // 19 'addListener', // 20 'removeListener', // 21 + 'connectAnimatedNodeToShadowNodeFamily', // 22 ]; const nativeOperations: { [$Values]: (...$ReadOnlyArray) => void, @@ -312,6 +314,16 @@ const API = { NativeOperations.connectAnimatedNodeToView(nodeTag, viewTag); }, + connectAnimatedNodeToShadowNodeFamily( + nodeTag: number, + shadowNode: Node, + ): void { + NativeOperations.connectAnimatedNodeToShadowNodeFamily?.( + nodeTag, + shadowNode, + ); + }, + disconnectAnimatedNodeFromView(nodeTag: number, viewTag: number): void { NativeOperations.disconnectAnimatedNodeFromView(nodeTag, viewTag); }, diff --git a/packages/react-native/src/private/specs_DEPRECATED/modules/NativeAnimatedModule.js b/packages/react-native/src/private/specs_DEPRECATED/modules/NativeAnimatedModule.js index 91f64cdcdc3929..f71e7f9dcf5c13 100644 --- a/packages/react-native/src/private/specs_DEPRECATED/modules/NativeAnimatedModule.js +++ b/packages/react-native/src/private/specs_DEPRECATED/modules/NativeAnimatedModule.js @@ -49,6 +49,10 @@ export interface Spec extends TurboModule { +flattenAnimatedNodeOffset: (nodeTag: number) => void; +extractAnimatedNodeOffset: (nodeTag: number) => void; +connectAnimatedNodeToView: (nodeTag: number, viewTag: number) => void; + +connectAnimatedNodeToShadowNodeFamily?: ( + nodeTag: number, + shadowNode: Object, + ) => void; +disconnectAnimatedNodeFromView: (nodeTag: number, viewTag: number) => void; +restoreDefaultValues: (nodeTag: number) => void; +dropAnimatedNode: (tag: number) => void; diff --git a/packages/react-native/src/private/specs_DEPRECATED/modules/NativeAnimatedTurboModule.js b/packages/react-native/src/private/specs_DEPRECATED/modules/NativeAnimatedTurboModule.js index 5a20ac1539de67..f67647c5a06c88 100644 --- a/packages/react-native/src/private/specs_DEPRECATED/modules/NativeAnimatedTurboModule.js +++ b/packages/react-native/src/private/specs_DEPRECATED/modules/NativeAnimatedTurboModule.js @@ -49,6 +49,10 @@ export interface Spec extends TurboModule { +flattenAnimatedNodeOffset: (nodeTag: number) => void; +extractAnimatedNodeOffset: (nodeTag: number) => void; +connectAnimatedNodeToView: (nodeTag: number, viewTag: number) => void; + +connectAnimatedNodeToShadowNodeFamily?: ( + nodeTag: number, + shadowNode: Object, + ) => void; +disconnectAnimatedNodeFromView: (nodeTag: number, viewTag: number) => void; +restoreDefaultValues: (nodeTag: number) => void; +dropAnimatedNode: (tag: number) => void;