Skip to content

Commit 47a4295

Browse files
committed
Pass committed view props to the platform routing predicate
1 parent 134269f commit 47a4295

8 files changed

Lines changed: 81 additions & 17 deletions

File tree

packages/react-native-reanimated/Common/cpp/reanimated/CSS/core/transition/CSSPlatformTransitionProxy.cpp

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <jsi/JSIDynamic.h>
44
#include <react/debug/react_native_assert.h>
55

6+
#include <unordered_set>
67
#include <utility>
78

89
namespace reanimated::css {
@@ -11,14 +12,20 @@ CSSPlatformTransitionProxy::CSSPlatformTransitionProxy(
1112
CSSCanRoutePropertyFunction canRoute,
1213
CSSCanExpressValueFunction canExpressValue,
1314
CSSApplyTransitionFunction applyTransition,
14-
CSSRemoveTransitionFunction removeTransition)
15+
CSSRemoveTransitionFunction removeTransition,
16+
std::shared_ptr<ViewStylesRepository> viewStylesRepository)
1517
: canRoute_(std::move(canRoute)),
1618
canExpressValue_(std::move(canExpressValue)),
1719
applyTransition_(std::move(applyTransition)),
18-
removeTransition_(std::move(removeTransition)) {}
19-
20-
bool CSSPlatformTransitionProxy::canRoute(const std::string &propertyName, const EasingConfig &easing) const {
21-
return canRoute_ && canRoute_(propertyName, easing);
20+
removeTransition_(std::move(removeTransition)),
21+
viewStylesRepository_(std::move(viewStylesRepository)) {}
22+
23+
bool CSSPlatformTransitionProxy::canRoute(
24+
const std::string &propertyName,
25+
const EasingConfig &easing,
26+
const ShadowNode &shadowNode,
27+
const std::unordered_set<std::string> &transitioningProperties) const {
28+
return canRoute_ && canRoute_(propertyName, easing, shadowNode, transitioningProperties);
2229
}
2330

2431
bool CSSPlatformTransitionProxy::canExpressValue(const std::string &propertyName, const folly::dynamic &value) const {
@@ -43,11 +50,21 @@ void CSSPlatformTransitionProxy::remove(const Tag viewTag, const std::string &pr
4350
// the prop is migrating sides - that's how we emit cancels.
4451
CSSPlatformTransitionProxy::ProcessedConfig CSSPlatformTransitionProxy::processConfig(
4552
jsi::Runtime &rt,
53+
const std::shared_ptr<const ShadowNode> &shadowNode,
4654
CSSTransitionConfig &&config,
4755
const CSSTransitionRouting &previousRouting) const {
4856
ProcessedConfig result;
4957
result.routing = previousRouting;
5058

59+
// Eligibility is decided against the view's latest committed props.
60+
const auto newestShadowNode = viewStylesRepository_->getNewestShadowNode(shadowNode);
61+
62+
std::unordered_set<std::string> transitioningNames;
63+
transitioningNames.reserve(config.changedPropertiesSettings.size());
64+
for (const auto &entry : config.changedPropertiesSettings) {
65+
transitioningNames.insert(entry.first);
66+
}
67+
5168
// Drain changedPropertiesSettings; for each, decide routing and bucket.
5269
// extract() preserves move-only PropertyValueDiff (jsi::Value pair).
5370
while (!config.changedPropertiesSettings.empty()) {
@@ -56,7 +73,7 @@ CSSPlatformTransitionProxy::ProcessedConfig CSSPlatformTransitionProxy::processC
5673
const auto &settings = settingsNode.mapped();
5774
const auto valueIt = config.changedProperties.find(propertyName);
5875

59-
bool routable = canRoute(propertyName, settings.easingConfig);
76+
bool routable = canRoute(propertyName, settings.easingConfig, *newestShadowNode, transitioningNames);
6077
folly::dynamic fromValue;
6178
folly::dynamic toValue;
6279
if (routable && valueIt != config.changedProperties.end()) {

packages/react-native-reanimated/Common/cpp/reanimated/CSS/core/transition/CSSPlatformTransitionProxy.h

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,17 @@
33
#include <reanimated/CSS/common/definitions.h>
44
#include <reanimated/CSS/configs/CSSTransitionConfig.h>
55
#include <reanimated/CSS/easing/EasingConfigs.h>
6+
#include <reanimated/CSS/misc/ViewStylesRepository.h>
67

78
#include <folly/dynamic.h>
89
#include <jsi/jsi.h>
910
#include <react/renderer/core/ReactPrimitives.h>
11+
#include <react/renderer/core/ShadowNode.h>
1012

1113
#include <functional>
14+
#include <memory>
1215
#include <string>
16+
#include <unordered_set>
1317
#include <vector>
1418

1519
namespace reanimated::css {
@@ -46,8 +50,15 @@ struct CSSPlatformTransitionConfig {
4650
}
4751
};
4852

49-
// Whether the platform can drive the property natively for the given easing.
50-
using CSSCanRoutePropertyFunction = std::function<bool(const std::string &propertyName, const EasingConfig &easing)>;
53+
// Whether the platform can drive the property natively. The shadow node
54+
// carries the view's latest committed props and transitioningProperties lists
55+
// the props changing in the same routing pass, so platform implementations can
56+
// reject properties whose rendering depends on sibling style.
57+
using CSSCanRoutePropertyFunction = std::function<bool(
58+
const std::string &propertyName,
59+
const EasingConfig &easing,
60+
const ShadowNode &shadowNode,
61+
const std::unordered_set<std::string> &transitioningProperties)>;
5162
// Whether the platform can express the given value for the property (cheap
5263
// shape check; the actual conversion happens in the apply callback).
5364
using CSSCanExpressValueFunction = std::function<bool(const std::string &propertyName, const folly::dynamic &value)>;
@@ -71,7 +82,8 @@ class CSSPlatformTransitionProxy {
7182
CSSCanRoutePropertyFunction canRoute,
7283
CSSCanExpressValueFunction canExpressValue,
7384
CSSApplyTransitionFunction applyTransition,
74-
CSSRemoveTransitionFunction removeTransition);
85+
CSSRemoveTransitionFunction removeTransition,
86+
std::shared_ptr<ViewStylesRepository> viewStylesRepository);
7587

7688
void run(const CSSPlatformTransitionPropertyConfig &config) const;
7789
void remove(Tag viewTag, const std::string &propertyName) const;
@@ -83,16 +95,24 @@ class CSSPlatformTransitionProxy {
8395
// A property routes to the platform only when the platform declares both the
8496
// property and its values expressible; otherwise it goes to the loop, which
8597
// can animate everything.
86-
ProcessedConfig
87-
processConfig(jsi::Runtime &rt, CSSTransitionConfig &&config, const CSSTransitionRouting &previousRouting) const;
98+
ProcessedConfig processConfig(
99+
jsi::Runtime &rt,
100+
const std::shared_ptr<const ShadowNode> &shadowNode,
101+
CSSTransitionConfig &&config,
102+
const CSSTransitionRouting &previousRouting) const;
88103

89104
private:
90-
bool canRoute(const std::string &propertyName, const EasingConfig &easing) const;
105+
bool canRoute(
106+
const std::string &propertyName,
107+
const EasingConfig &easing,
108+
const ShadowNode &shadowNode,
109+
const std::unordered_set<std::string> &transitioningProperties) const;
91110

92111
CSSCanRoutePropertyFunction canRoute_;
93112
CSSCanExpressValueFunction canExpressValue_;
94113
CSSApplyTransitionFunction applyTransition_;
95114
CSSRemoveTransitionFunction removeTransition_;
115+
std::shared_ptr<ViewStylesRepository> viewStylesRepository_;
96116
};
97117

98118
} // namespace reanimated::css

packages/react-native-reanimated/Common/cpp/reanimated/CSS/core/transition/CSSTransition.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ folly::dynamic CSSTransition::run(jsi::Runtime &rt, CSSTransitionConfig &&config
3838

3939
// CSSTransition owns routing: platform-routed props run immediately on the platform
4040
// transition; the loop-routed remainder is applied to the loop transition below.
41-
auto processed = platformTransitionProxy_->processConfig(rt, std::move(config), routing_);
41+
auto processed = platformTransitionProxy_->processConfig(rt, shadowNode_, std::move(config), routing_);
4242
routing_ = std::move(processed.routing);
4343

4444
if (!processed.platform.empty()) {

packages/react-native-reanimated/Common/cpp/reanimated/CSS/misc/ViewStylesRepository.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,15 @@ folly::dynamic ViewStylesRepository::getStyleProp(const Tag tag, const PropertyP
7474
return getPropertyValue(staticPropsRegistry_->get(tag), propertyPath);
7575
}
7676

77+
std::shared_ptr<const ShadowNode> ViewStylesRepository::getNewestShadowNode(
78+
const std::shared_ptr<const ShadowNode> &shadowNode) {
79+
if (!uiManager_) {
80+
return shadowNode;
81+
}
82+
auto newestClone = uiManager_->getNewestCloneOfShadowNode(*shadowNode);
83+
return newestClone ? newestClone : shadowNode;
84+
}
85+
7786
void ViewStylesRepository::clearNodesCache() {
7887
shadowNodeCache_.clear();
7988
}

packages/react-native-reanimated/Common/cpp/reanimated/CSS/misc/ViewStylesRepository.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ class ViewStylesRepository {
3636
jsi::Value getParentNodeProp(const std::shared_ptr<const ShadowNode> &shadowNode, const std::string &propName);
3737
folly::dynamic getStyleProp(Tag tag, const PropertyPath &propertyPath);
3838

39+
// Resolves the latest committed clone of the node (the caller's reference may
40+
// be stale); falls back to the given node when no newer clone exists.
41+
std::shared_ptr<const ShadowNode> getNewestShadowNode(const std::shared_ptr<const ShadowNode> &shadowNode);
42+
3943
void clearNodesCache();
4044

4145
private:

packages/react-native-reanimated/Common/cpp/reanimated/NativeModules/ReanimatedModuleProxy.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,8 @@ ReanimatedModuleProxy::ReanimatedModuleProxy(
224224
platformDepMethodsHolder.cssCanRouteProperty,
225225
platformDepMethodsHolder.cssCanExpressValue,
226226
platformDepMethodsHolder.cssApplyTransition,
227-
platformDepMethodsHolder.cssRemoveTransition))),
227+
platformDepMethodsHolder.cssRemoveTransition,
228+
viewStylesRepository_))),
228229
pseudoStylesRegistry_(std::make_shared<PseudoStylesRegistry>(
229230
platformDepMethodsHolder.attachPseudoSelector,
230231
platformDepMethodsHolder.detachPseudoSelector,

packages/react-native-reanimated/apple/reanimated/apple/CSS/REACSSTransitionRouting.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,17 @@
22

33
#import <reanimated/CSS/easing/EasingConfigs.h>
44

5+
#import <react/renderer/core/ShadowNode.h>
6+
57
#import <string>
8+
#import <unordered_set>
69

710
// Routing predicate for platform-driven CSS transitions: whether Core
8-
// Animation can drive the property natively for the given easing.
9-
bool canRouteCSSProperty(const std::string &propertyName, const reanimated::css::EasingConfig &easing);
11+
// Animation can drive the property natively. The shadow node carries the
12+
// view's latest committed props; transitioningProperties lists the props
13+
// changing in the same routing pass.
14+
bool canRouteCSSProperty(
15+
const std::string &propertyName,
16+
const reanimated::css::EasingConfig &easing,
17+
const facebook::react::ShadowNode &shadowNode,
18+
const std::unordered_set<std::string> &transitioningProperties);

packages/react-native-reanimated/apple/reanimated/apple/CSS/REACSSTransitionRouting.mm

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@
66

77
using namespace reanimated::css;
88

9-
bool canRouteCSSProperty(const std::string &propertyName, const EasingConfig &easing)
9+
bool canRouteCSSProperty(
10+
const std::string &propertyName,
11+
const EasingConfig &easing,
12+
const facebook::react::ShadowNode & /*shadowNode*/,
13+
const std::unordered_set<std::string> & /*transitioningProperties*/)
1014
{
1115
if constexpr (!reanimated::StaticFeatureFlags::getFlag("IOS_CSS_CORE_ANIMATION")) {
1216
return false;

0 commit comments

Comments
 (0)