11#include < reanimated/CSS/core/transition/CSSPlatformTransitionProxy.h>
2- #include < reanimated/Tools/FeatureFlags.h>
32
43#include < react/debug/react_native_assert.h>
54
65#include < utility>
76
87namespace reanimated ::css {
98
9+ namespace {
10+
11+ // Reduces a jsi::Value transition endpoint to the representation-agnostic shape
12+ // the platform parses (number / size / null).
13+ CSSPropertyValue endpointFromJSI (jsi::Runtime &rt, const jsi::Value &value) {
14+ CSSPropertyValue result;
15+ if (value.isNull () || value.isUndefined ()) {
16+ result.isNull = true ;
17+ } else if (value.isNumber ()) {
18+ result.number = value.asNumber ();
19+ } else if (value.isObject ()) {
20+ const auto object = value.asObject (rt);
21+ const auto width = object.getProperty (rt, " width" );
22+ const auto height = object.getProperty (rt, " height" );
23+ result.size = std::array<double , 2 >{
24+ width.isNumber () ? width.asNumber () : 0.0 ,
25+ height.isNumber () ? height.asNumber () : 0.0 ,
26+ };
27+ }
28+ return result;
29+ }
30+
31+ // The same reduction for the runtime-free pseudo-selector toggle path.
32+ CSSPropertyValue endpointFromDynamic (const folly::dynamic &value) {
33+ CSSPropertyValue result;
34+ if (value.isNull ()) {
35+ result.isNull = true ;
36+ } else if (value.isNumber ()) {
37+ result.number = value.asDouble ();
38+ } else if (value.isObject ()) {
39+ const auto *width = value.get_ptr (" width" );
40+ const auto *height = value.get_ptr (" height" );
41+ result.size = std::array<double , 2 >{
42+ width != nullptr && width->isNumber () ? width->asDouble () : 0.0 ,
43+ height != nullptr && height->isNumber () ? height->asDouble () : 0.0 ,
44+ };
45+ }
46+ return result;
47+ }
48+
49+ } // namespace
50+
1051CSSPlatformTransitionProxy::CSSPlatformTransitionProxy (
1152 CSSCanRoutePropertyFunction canRoute,
53+ CSSParseValueFunction parseValue,
1254 CSSApplyTransitionFunction applyTransition,
1355 CSSRemoveTransitionFunction removeTransition)
1456 : canRoute_(std::move(canRoute)),
57+ parseValue_ (std::move(parseValue)),
1558 applyTransition_(std::move(applyTransition)),
1659 removeTransition_(std::move(removeTransition)) {}
1760
1861bool CSSPlatformTransitionProxy::canRoute (const std::string &propertyName, const EasingConfig &easing) const {
19- if constexpr (!StaticFeatureFlags::getFlag (" IOS_CSS_CORE_ANIMATION" )) {
20- return false ;
21- }
2262 return canRoute_ && canRoute_ (propertyName, easing);
2363}
2464
65+ std::optional<PlatformValue> CSSPlatformTransitionProxy::parseValue (
66+ const std::string &propertyName,
67+ const CSSPropertyValue &value) const {
68+ return parseValue_ ? parseValue_ (propertyName, value) : std::nullopt ;
69+ }
70+
2571void CSSPlatformTransitionProxy::run (const CSSPlatformTransitionPropertyConfig &config) const {
2672 if (applyTransition_) {
2773 applyTransition_ (config);
@@ -34,35 +80,42 @@ void CSSPlatformTransitionProxy::remove(const Tag viewTag, const std::string &pr
3480 }
3581}
3682
37- // Splits the new split-shape config into loop / platform buckets. result.routing
38- // starts as a copy of the previous call's routing and is updated as we route
39- // each prop; erasing from the *other* side's set returns nonzero exactly when
40- // the prop is migrating sides - that's how we emit cancels.
83+ // Erasing from the other side's routing set returns nonzero exactly when the
84+ // property migrates sides - that's when the old side gets a cancel.
4185CSSPlatformTransitionProxy::ProcessedConfig CSSPlatformTransitionProxy::processConfig (
86+ jsi::Runtime &rt,
4287 CSSTransitionConfig &&config,
4388 const CSSTransitionRouting &previousRouting) const {
4489 ProcessedConfig result;
4590 result.routing = previousRouting;
4691
47- // Drain changedPropertiesSettings; for each, decide routing and bucket.
48- // extract() preserves move-only PropertyValueDiff (jsi::Value pair).
92+ // extract() preserves the move-only jsi::Value diffs.
4993 while (!config.changedPropertiesSettings .empty ()) {
5094 auto settingsNode = config.changedPropertiesSettings .extract (config.changedPropertiesSettings .begin ());
5195 const auto &propertyName = settingsNode.key ();
5296 const auto &settings = settingsNode.mapped ();
5397 const auto valueIt = config.changedProperties .find (propertyName);
5498
55- if (canRoute (propertyName, settings.easingConfig )) {
99+ bool routable = canRoute (propertyName, settings.easingConfig );
100+ std::optional<PlatformValue> fromValue;
101+ std::optional<PlatformValue> toValue;
102+ if (routable && valueIt != config.changedProperties .end ()) {
103+ fromValue = parseValue (propertyName, endpointFromJSI (rt, valueIt->second .first ));
104+ toValue = parseValue (propertyName, endpointFromJSI (rt, valueIt->second .second ));
105+ routable = fromValue.has_value () && toValue.has_value ();
106+ }
107+
108+ if (routable) {
56109 // loop -> platform migration: cancel on loop.
57110 if (result.routing .loop .erase (propertyName) > 0 ) {
58111 result.loop .removedProperties .push_back (propertyName);
59112 }
60113 result.routing .platform .insert (propertyName);
61114
62115 if (valueIt != config.changedProperties .end ()) {
63- auto valueNode = config.changedProperties .extract (valueIt);
116+ config.changedProperties .erase (valueIt);
64117 result.platform .changedProperties .push_back (
65- CSSPlatformTransitionRawEntry {propertyName, std::move (valueNode. mapped ()) , settings});
118+ CSSPlatformTransitionEntry {propertyName, *fromValue, *toValue , settings});
66119 }
67120 result.platform .changedPropertiesSettings .insert (std::move (settingsNode));
68121 } else {
@@ -84,8 +137,7 @@ CSSPlatformTransitionProxy::ProcessedConfig CSSPlatformTransitionProxy::processC
84137 // have consumed all of changedProperties.
85138 react_native_assert (config.changedProperties .empty () && " [Reanimated] CSS transition value diff without settings" );
86139
87- // Props JS asked to stop transitioning: look up the owning side in routing
88- // and forward the cancel there.
140+ // Forward removal cancels to the side that owns the property.
89141 for (auto &propertyName : config.removedProperties ) {
90142 if (result.routing .platform .erase (propertyName) > 0 ) {
91143 result.platform .removedProperties .push_back (std::move (propertyName));
@@ -97,4 +149,25 @@ CSSPlatformTransitionProxy::ProcessedConfig CSSPlatformTransitionProxy::processC
97149 return result;
98150}
99151
152+ CSSPlatformTransitionProxy::ProcessedDynamicDiffs CSSPlatformTransitionProxy::processDynamicDiffs (
153+ const CSSTransitionRouting &routing,
154+ const PropertyValueDynamicDiffsMap &propertyDiffs) const {
155+ ProcessedDynamicDiffs result;
156+ for (const auto &[propertyName, propertyDiff] : propertyDiffs) {
157+ // The routing was decided when the transition was registered; here we only
158+ // re-parse the toggled endpoints. Values the platform cannot express fall
159+ // back to the loop.
160+ if (routing.platform .contains (propertyName)) {
161+ auto fromValue = parseValue (propertyName, endpointFromDynamic (propertyDiff.first ));
162+ auto toValue = parseValue (propertyName, endpointFromDynamic (propertyDiff.second ));
163+ if (fromValue && toValue) {
164+ result.platform .emplace (propertyName, std::make_pair (*fromValue, *toValue));
165+ continue ;
166+ }
167+ }
168+ result.loop .emplace (propertyName, propertyDiff);
169+ }
170+ return result;
171+ }
172+
100173} // namespace reanimated::css
0 commit comments