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

fix: CSS transition shorthand property behavior in react-native-web #7019

Open
wants to merge 6 commits into
base: @matipl01/css-keyframes-registry
Choose a base branch
from

Conversation

MatiPl01
Copy link
Member

@MatiPl01 MatiPl01 commented Feb 11, 2025

Summary

This PR fixes CSS transition properties being overridden by react-native-web. It happened because we didn't filter out CSS props from the style object passed to the component in the render() method of the AnimatedComponent.

I also made a few other changes to ensure that the transition shorthand is validated on web as well and preprocessed in a similar way to the native implementation.

Example Recordings

In the previous implementation, the transitionTimingFunction prop specified before the transition property shorthand was overriding the transition prop easing. Web also shown an error in the console that shorthand props shouldn't be mixed with longhand ones. We don't want this error to show up and want to support usage of both at the same time.

Web

Before After
Screen.Recording.2025-02-13.at.14.28.49.mp4
Screen.Recording.2025-02-13.at.14.24.37.mp4

iOS

This recording is just for comparison to see that the behavior on web is also correct (the same as on the recording below) after changes implemented in this PR

Simulator.Screen.Recording.-.iPhone.16.Pro.-.2025-02-13.at.14.25.02.mp4
Source code
/* eslint-disable perfectionist/sort-objects */
import React, { useReducer } from 'react';
import { Button, StyleSheet, View } from 'react-native';
import { createAnimatedComponent, steps } from 'react-native-reanimated';

const AnimatedView = createAnimatedComponent(View);

export default function EmptyExample() {
  const [state, toggleState] = useReducer((s) => !s, false);

  return (
    <View style={styles.container}>
      <AnimatedView
        style={{
          width: state ? 200 : 100,
          height: state ? 200 : 100,
          transform: [{ rotate: state ? '45deg' : '0deg' }],
          transitionTimingFunction: steps(2), // overridden by the shorthand
          backgroundColor: 'red',
          transition:
            '5s cubic-bezier(0, -0.54, 1, -0.5), transform 2s ease-in',
          transitionDuration: 1000, // overrides the shorthand
        }}
      />
      <Button title="Toggle width" onPress={toggleState} />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    alignItems: 'center',
    flex: 1,
    justifyContent: 'center',
  },
});

@MatiPl01 MatiPl01 self-assigned this Feb 11, 2025
@MatiPl01 MatiPl01 force-pushed the @matipl01/css-keyframes-registry branch from 4758801 to 61992a0 Compare February 13, 2025 16:27
@MatiPl01 MatiPl01 force-pushed the @matipl01/fix-web-css-transition-shorthand branch from 8a31475 to 1d01d03 Compare February 13, 2025 16:28
) => `Invalid transition property "${JSON.stringify(transitionProperty)}"`,
};

function getExpandedConfigProperties(
config: CSSTransitionProperties
): ExpandedConfigProperties {
const configEntries = Object.entries(config);
const shorthandIndex = config.transition
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved this removal of transition properties listed before the transition shorthand property to the filterCSSAndStyleProperties because it simplifies the logic and removing invalid properties as soon as possible seems to be a better solution for me.

Comment on lines +27 to +45
return splitByComma(value).reduce<ExpandedCSSTransitionConfigProperties>(
(acc, part) => {
const result = parseSingleTransitionShorthand(part);
acc.transitionProperty.push(result.transitionProperty ?? 'all');
acc.transitionDuration.push(
result.transitionDuration ? String(result.transitionDuration) : '0s'
);
acc.transitionTimingFunction.push(
result.transitionTimingFunction ?? 'ease'
);
acc.transitionDelay.push(
result.transitionDelay ? String(result.transitionDelay) : '0s'
);
acc.transitionBehavior.push(result.transitionBehavior ?? 'normal');
return acc;
},
createEmptyTransitionConfig()
);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I decided to parse the transition shorthand on web as well in order to:

  1. Ensure that behavior is always the same as in the mobile implementation
  2. Because parseSingleTransitionShorthand already validates a correctness of the transition property shorthand

@MatiPl01 MatiPl01 marked this pull request as ready for review February 13, 2025 16:54
@MatiPl01 MatiPl01 requested a review from tomekzaw February 13, 2025 16:54
@MatiPl01 MatiPl01 force-pushed the @matipl01/css-keyframes-registry branch from 61992a0 to 2db4ac2 Compare February 15, 2025 23:05
@MatiPl01 MatiPl01 force-pushed the @matipl01/fix-web-css-transition-shorthand branch from 39a007a to eb04501 Compare February 15, 2025 23:16
Copy link
Member

@piaskowyk piaskowyk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't tested it, but I didn't find anything controversial in these changes, so I can approve it 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants