Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add support for multiple transitionBehavior property settings in CSS transitions #6972

Merged
merged 4 commits into from
Feb 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,22 @@

namespace reanimated {

std::optional<CSSTransitionPropertySettings> getTransitionPropertySettings(
const CSSTransitionPropertiesSettings &propertiesSettings,
const std::string &propName) {
// Try to use property specific settings first
const auto &propIt = propertiesSettings.find(propName);
if (propIt != propertiesSettings.end()) {
return propertiesSettings.at(propName);
}
// Fallback to "all" settings if no property specific settings are available
if (propertiesSettings.find("all") != propertiesSettings.end()) {
return propertiesSettings.at("all");
}
// Or return nullopt if no settings are available
return std::nullopt;
}

TransitionProperties getProperties(
jsi::Runtime &rt,
const jsi::Object &config) {
Expand All @@ -24,6 +40,10 @@ TransitionProperties getProperties(
return std::nullopt;
}

bool getAllowDiscrete(jsi::Runtime &rt, const jsi::Object &config) {
return config.getProperty(rt, "allowDiscrete").asBool();
}

CSSTransitionPropertiesSettings parseCSSTransitionPropertiesSettings(
jsi::Runtime &rt,
const jsi::Object &settings) {
Expand All @@ -44,7 +64,8 @@ CSSTransitionPropertiesSettings parseCSSTransitionPropertiesSettings(
CSSTransitionPropertySettings{
getDuration(rt, propertySettings),
getTimingFunction(rt, propertySettings),
getDelay(rt, propertySettings)});
getDelay(rt, propertySettings),
getAllowDiscrete(rt, propertySettings)});
}

return result;
Expand All @@ -57,8 +78,7 @@ CSSTransitionConfig parseCSSTransitionConfig(
return CSSTransitionConfig{
getProperties(rt, configObj),
parseCSSTransitionPropertiesSettings(
rt, configObj.getProperty(rt, "settings").asObject(rt)),
configObj.getProperty(rt, "allowDiscrete").asBool()};
rt, configObj.getProperty(rt, "settings").asObject(rt))};
}

PartialCSSTransitionConfig parsePartialCSSTransitionConfig(
Expand All @@ -75,9 +95,6 @@ PartialCSSTransitionConfig parsePartialCSSTransitionConfig(
result.settings = parseCSSTransitionPropertiesSettings(
rt, partialObj.getProperty(rt, "settings").asObject(rt));
}
if (partialObj.hasProperty(rt, "allowDiscrete")) {
result.allowDiscrete = partialObj.getProperty(rt, "allowDiscrete").asBool();
}

return result;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ struct CSSTransitionPropertySettings {
double duration;
EasingFunction easingFunction;
double delay;
bool allowDiscrete;
};

using CSSTransitionPropertiesSettings =
Expand All @@ -22,15 +23,17 @@ using CSSTransitionPropertiesSettings =
struct CSSTransitionConfig {
TransitionProperties properties;
CSSTransitionPropertiesSettings settings;
bool allowDiscrete;
};

struct PartialCSSTransitionConfig {
std::optional<TransitionProperties> properties;
std::optional<CSSTransitionPropertiesSettings> settings;
std::optional<bool> allowDiscrete;
};

std::optional<CSSTransitionPropertySettings> getTransitionPropertySettings(
const CSSTransitionPropertiesSettings &propertiesSettings,
const std::string &propName);

TransitionProperties getProperties(jsi::Runtime &rt, const jsi::Object &config);

CSSTransitionPropertiesSettings parseCSSTransitionPropertiesSettings(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ CSSTransition::CSSTransition(
const CSSTransitionConfig &config,
const std::shared_ptr<ViewStylesRepository> &viewStylesRepository)
: shadowNode_(std::move(shadowNode)),
properties_(config.properties),
allowDiscrete_(config.allowDiscrete),
viewStylesRepository_(viewStylesRepository),
progressProvider_(TransitionProgressProvider(config.settings)),
properties_(config.properties),
settings_(config.settings),
progressProvider_(TransitionProgressProvider()),
styleInterpolator_(TransitionStyleInterpolator(viewStylesRepository)) {}

Tag CSSTransition::getViewTag() const {
Expand All @@ -22,14 +22,6 @@ ShadowNode::Shared CSSTransition::getShadowNode() const {
return shadowNode_;
}

const TransitionProperties &CSSTransition::getProperties() const {
return properties_;
}

bool CSSTransition::getAllowDiscrete() const {
return allowDiscrete_;
}

double CSSTransition::getMinDelay(double timestamp) const {
return progressProvider_.getMinDelay(timestamp);
}
Expand All @@ -42,15 +34,57 @@ jsi::Value CSSTransition::getCurrentInterpolationStyle(jsi::Runtime &rt) const {
return styleInterpolator_.getCurrentInterpolationStyle(rt, shadowNode_);
}

PropertyNames CSSTransition::getAllowedProperties(
MatiPl01 marked this conversation as resolved.
Show resolved Hide resolved
jsi::Runtime &rt,
const jsi::Value &oldProps,
const jsi::Value &newProps) {
if (!oldProps.isObject() || !newProps.isObject()) {
return {};
}

// If specific properties are set, process only those
if (properties_.has_value()) {
PropertyNames allowedProps;
const auto &properties = properties_.value();
allowedProps.reserve(properties.size());

for (const auto &prop : properties) {
if (isAllowedProperty(prop)) {
allowedProps.push_back(prop);
}
}

return allowedProps;
}

// Process all properties from both old and new props
std::unordered_set<std::string> allAllowedProps;

auto processProps = [&](const jsi::Object &propsObj) {
const auto &propertyNames = propsObj.getPropertyNames(rt);
const size_t size = propertyNames.size(rt);

for (size_t i = 0; i < size; i++) {
const auto &propertyName =
propertyNames.getValueAtIndex(rt, i).asString(rt).utf8(rt);
if (isAllowedProperty(propertyName)) {
allAllowedProps.insert(propertyName);
}
}
};

processProps(oldProps.asObject(rt));
processProps(newProps.asObject(rt));

return {allAllowedProps.begin(), allAllowedProps.end()};
}

void CSSTransition::updateSettings(const PartialCSSTransitionConfig &config) {
if (config.properties.has_value()) {
updateTransitionProperties(config.properties.value());
}
if (config.allowDiscrete.has_value()) {
allowDiscrete_ = config.allowDiscrete.value();
}
if (config.settings.has_value()) {
progressProvider_.setSettings(config.settings.value());
settings_ = config.settings.value();
MatiPl01 marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand All @@ -60,6 +94,7 @@ jsi::Value CSSTransition::run(
const double timestamp) {
progressProvider_.runProgressProviders(
timestamp,
settings_,
changedProps.changedPropertyNames,
styleInterpolator_.getReversedPropertyNames(rt, changedProps.newProps));
styleInterpolator_.updateInterpolatedProperties(
Expand All @@ -85,10 +120,25 @@ void CSSTransition::updateTransitionProperties(

const std::unordered_set<std::string> transitionPropertyNames(
properties_->begin(), properties_->end());

styleInterpolator_.discardIrrelevantInterpolators(transitionPropertyNames);
progressProvider_.discardIrrelevantProgressProviders(transitionPropertyNames);
}

bool CSSTransition::isAllowedProperty(const std::string &propName) const {
if (!isDiscreteProperty(propName)) {
return true;
}

const auto &propertySettings =
getTransitionPropertySettings(settings_, propName);
MatiPl01 marked this conversation as resolved.
Show resolved Hide resolved

if (!propertySettings.has_value()) {
return false;
}
return propertySettings.value().allowDiscrete;
}

} // namespace reanimated

#endif // RCT_NEW_ARCH_ENABLED
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@ class CSSTransition {

Tag getViewTag() const;
ShadowNode::Shared getShadowNode() const;
const TransitionProperties &getProperties() const;
bool getAllowDiscrete() const;
double getMinDelay(double timestamp) const;
TransitionProgressState getState() const;
jsi::Value getCurrentInterpolationStyle(jsi::Runtime &rt) const;
PropertyNames getAllowedProperties(
jsi::Runtime &rt,
const jsi::Value &oldProps,
const jsi::Value &newProps);

void updateSettings(const PartialCSSTransitionConfig &config);
jsi::Value
Expand All @@ -35,13 +37,14 @@ class CSSTransition {

private:
const ShadowNode::Shared shadowNode_;
TransitionProperties properties_;
bool allowDiscrete_;
const std::shared_ptr<ViewStylesRepository> viewStylesRepository_;
TransitionProperties properties_;
CSSTransitionPropertiesSettings settings_;
TransitionProgressProvider progressProvider_;
TransitionStyleInterpolator styleInterpolator_;

void updateTransitionProperties(const TransitionProperties &properties);
bool isAllowedProperty(const std::string &propName) const;
};

} // namespace reanimated
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ void ViewStylesRepository::updateCacheIfNeeded(
jsi::Value ViewStylesRepository::getPropertyValue(
jsi::Runtime &rt,
const folly::dynamic &value,
const std::vector<std::string> &propertyPath) {
const PropertyPath &propertyPath) {
const folly::dynamic *currentValue = &value;

for (size_t i = 0; i < propertyPath.size(); ++i) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,15 +76,6 @@ double TransitionPropertyProgressProvider::getElapsedTime(

// TransitionProgressProvider

TransitionProgressProvider::TransitionProgressProvider(
const CSSTransitionPropertiesSettings &settings)
: settings_(std::move(settings)) {}

void TransitionProgressProvider::setSettings(
const CSSTransitionPropertiesSettings &settings) {
settings_ = settings;
}

TransitionProgressState TransitionProgressProvider::getState() const {
for (const auto &[_, propertyProgressProvider] : propertyProgressProviders_) {
if (propertyProgressProvider->getState() ==
Expand Down Expand Up @@ -139,15 +130,24 @@ void TransitionProgressProvider::discardIrrelevantProgressProviders(

void TransitionProgressProvider::runProgressProviders(
const double timestamp,
const CSSTransitionPropertiesSettings &propertiesSettings,
const PropertyNames &changedPropertyNames,
const std::unordered_set<std::string> &reversedPropertyNames) {
for (const auto &propertyName : changedPropertyNames) {
const auto propertySettings = getPropertySettings(propertyName);
const auto progressProviderIt =
propertyProgressProviders_.find(propertyName);
const auto propertySettingsOptional =
getTransitionPropertySettings(propertiesSettings, propertyName);

if (!propertySettingsOptional.has_value()) {
throw std::invalid_argument(
"[Reanimated] Property '" + propertyName +
"' is not a valid transition property");
}

const auto &propertySettings = propertySettingsOptional.value();
const auto it = propertyProgressProviders_.find(propertyName);

if (progressProviderIt != propertyProgressProviders_.end()) {
const auto &progressProvider = progressProviderIt->second;
if (it != propertyProgressProviders_.end()) {
const auto &progressProvider = it->second;
progressProvider->update(timestamp);

if (reversedPropertyNames.find(propertyName) !=
Expand Down Expand Up @@ -192,15 +192,6 @@ void TransitionProgressProvider::update(const double timestamp) {
}
}

CSSTransitionPropertySettings TransitionProgressProvider::getPropertySettings(
const std::string &propertyName) const {
// Find property settings or fallback to "all" settings if no property
// specific settings are available
const auto propertySettingsIt = settings_.find(propertyName);
return (propertySettingsIt != settings_.end()) ? propertySettingsIt->second
: settings_.at("all");
}

std::shared_ptr<TransitionPropertyProgressProvider>
TransitionProgressProvider::createReversingShorteningProgressProvider(
const double timestamp,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,6 @@ using TransitionPropertyProgressProviders = std::unordered_map<

class TransitionProgressProvider final {
public:
explicit TransitionProgressProvider(
const CSSTransitionPropertiesSettings &settings);

void setSettings(const CSSTransitionPropertiesSettings &settings);

TransitionProgressState getState() const;
double getMinDelay(double timestamp) const;
TransitionPropertyProgressProviders getPropertyProgressProviders() const;
Expand All @@ -73,18 +68,16 @@ class TransitionProgressProvider final {
const std::unordered_set<std::string> &transitionPropertyNames);
void runProgressProviders(
double timestamp,
const CSSTransitionPropertiesSettings &propertiesSettings,
const PropertyNames &changedPropertyNames,
const std::unordered_set<std::string> &reversedPropertyNames);
void update(double timestamp);

private:
CSSTransitionPropertiesSettings settings_;
TransitionPropertyProgressProviders propertyProgressProviders_;

std::unordered_set<std::string> removedProperties_;

CSSTransitionPropertySettings getPropertySettings(
const std::string &propertyName) const;
std::shared_ptr<TransitionPropertyProgressProvider>
createReversingShorteningProgressProvider(
double timestamp,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,12 +128,11 @@ PropsObserver CSSTransitionsRegistry::createPropsObserver(const Tag viewTag) {
}

const auto &transition = strongThis->registry_.at(viewTag);
const auto changedProps = getChangedProps(
rt,
oldProps,
newProps,
transition->getAllowDiscrete(),
transition->getProperties());
const auto allowedProperties =
transition->getAllowedProperties(rt, oldProps, newProps);

const auto changedProps =
getChangedProps(rt, oldProps, newProps, allowedProperties);

if (changedProps.changedPropertyNames.empty()) {
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace reanimated {

std::shared_ptr<PropertyInterpolator> createPropertyInterpolator(
const std::string &propertyName,
const std::vector<std::string> &propertyPath,
const PropertyPath &propertyPath,
const InterpolatorFactoriesRecord &factories,
const std::shared_ptr<KeyframeProgressProvider> &progressProvider,
const std::shared_ptr<ViewStylesRepository> &viewStylesRepository) {
Expand All @@ -26,7 +26,7 @@ std::shared_ptr<PropertyInterpolator> createPropertyInterpolator(

std::shared_ptr<PropertyInterpolator> createPropertyInterpolator(
size_t arrayIndex,
const std::vector<std::string> &propertyPath,
const PropertyPath &propertyPath,
const InterpolatorFactoriesArray &factories,
const std::shared_ptr<KeyframeProgressProvider> &progressProvider,
const std::shared_ptr<ViewStylesRepository> &viewStylesRepository) {
Expand Down
Loading
Loading