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

Proposition of builtin CSS transition handlers with react-transition-group #1036

Closed
ezsper opened this issue Jul 26, 2017 · 17 comments
Closed

Comments

@ezsper
Copy link

ezsper commented Jul 26, 2017

Most of the time transitions are hard and messy to perform and maintain, Styled Components bring us a very easy API to handle styling. I was thinking of an idea to add transition helpers to the API levered by react-transition-group and make it even better.

import styled from 'styled-components-transition-group';

// transition() wraps TransitionGroup
const List = styled.div.transition() ``;

// animated() wraps CSSTransition
const ListItem = styled.div.animated() `
  transition: opacity 300ms cubic-bezier(0.4, 0.0, 0.2, 1) 0ms;

  &:appear, &:enter, &:exit {
    opacity: 0;
  }
  &:appear-active, &:enter-active {
    opacity: 1;
  }
`;

Access my example repository and launch storybook for a working demo of this proposition.
storybook

@geelen
Copy link
Member

geelen commented Jul 27, 2017

Cool idea! My suggestion would be to have the API called animated and have it generate styled components, rather than injecting it into the existing API:

import { transition, animated } from 'styled-components-transition-group'

const List = transition.div``;

const ListItem = animated.div`
  transition: opacity 300ms cubic-bezier(0.4, 0.0, 0.2, 1) 0ms;

  &:appear, &:enter, &:exit {
    opacity: 0;
  }
  &:appear-active, &:enter-active {
    opacity: 1;
  }
`;

That way you could publish it as a separate package and get people playing with it. If we need to make some internal changes to SC to better facilitate packages like this, I'm open to that.

@ezsper
Copy link
Author

ezsper commented Jul 27, 2017

What I did in the example repository was not overriding any original function of the original package, but rather wrapping it.

The index.js

export { default as css } from './css';
export {
  keyframes,
  injectGlobal,
  ThemeProvider,
  withTheme,
  ServerStyleSheet,
  StyleSheetManager,
} from 'styled-components';
export { default } from './styled';

The css.js only wraps the original css function and throws an error when the user is trying to use :appear, :enter, :exit out of the animated method.

import {
  css as styledCSS,
} from 'styled-components';
import { transitionStyleRegExp } from './animated';

export default function css(strings, ...values) {
  const stylesheet = styledCSS(strings, ...values);
  if (transitionStyleRegExp.test(stylesheet)) {
    // eslint-disable-next-line no-console
    console.error(new Error('Using transition style out of animated'));
  }
  return stylesheet;
}

The styled.js wraps the original styled function, and inject the new methods, not overriding anything from the original module, only wrapping it and injecting the methods in the generated template function.

import styled from 'styled-components';
import domElements from 'styled-components/lib/utils/domElements';
import { injectStyledAnimate } from './animated';
import { injectStyledTransition } from './transition';

export default function styled2(MyComponent) {
  return injectStyledTransition(injectStyledAnimate(styled(MyComponent)));
}

domElements.forEach((domElement) => {
  styled2[domElement] = injectStyledTransition(injectStyledAnimate(styled[domElement]));
});

Notice that I even made available the original methods to be used with animated and transition.

These methods works.

styled.div ``
styled.div.attrs() ``
styled.div.config() ``
styled.div.animated() ``
styled.div.animated().attrs() ``
styled.div.animated().config() ``
styled.div.animated.attrs() ``
styled.div.animated.config() ``
styled.div.transition() ``
styled.div.transition().attrs() ``
styled.div.transition().config() ``
styled.div.transition.attrs() ``
styled.div.transition.config() ``
styled(MyComponent).animated() ``
styled(MyComponent).transition() ``

I'm thinking that removing the styled reference would be an issue...

  • It looses styled API reference
  • Forces the user to import styled and another library

On the other hand

  • If there are any other extending libraries for styled-components that the user might want to use, it would be a problem - as it forces an one library pattern.

I would rather believe that the user would create its on styled.js. In the example repository I also have exported the injection methods for animated and transition, so they can accomplish the same thing I did in the index.js and have other libraries injected.

But it would be nicer if styled-components attach some sort of extending methods for styled and css. So something like bellow come to place.

import { styledExtend, cssExtend } from 'styled-components';
import {
  animated,
  transition,
  animatedCSS,
} from 'styled-components-plugin-transition-group';

const styled = styledExtend({
  animated,
  transition,
});

export const css = cssExtend(animatedCSS);

export default styled;

export {
  keyframes,
  injectGlobal,
  ThemeProvider,
  withTheme,
  ServerStyleSheet,
  StyleSheetManager,
} from 'styled-components';

@wtgtybhertgeghgtwtg
Copy link

But it would be nicer if styled-components attach some sort of extending methods for styled and css. So something like bellow come to place.

Why? You already use injection in styled-components-transition-group, why not stick to that?

import originalStyled from 'styled-components';
import injectSomething from 'styled-components-something';

const styled = injectSomething(originalStyled);

It gets messy if you're injecting multiple things

import originalStyled from 'styled-components';
import injectSomething from 'styled-components-something';
import injectOr from 'styled-components-or';
import injectOther from 'styled-components-other;

const styled = injectSomething(injectOr(injectOther(originalStyled)));

but it's not particularly cleaner than a plugin system would be.

import {createStyled} from 'styled-components';
import something from 'styled-components-something';
import or from 'styled-components-or';
import other from 'styled-components-other;

const styled = createStyled({something, or, other});

@duro
Copy link

duro commented Oct 11, 2017

@ezsper I would love to make use of this, and I think it's a great idea to make it a separate package that does not require bundling into styled-components to get out the door.

@mxstbr
Copy link
Member

mxstbr commented Oct 11, 2017

We're not going to add any configuration to styled-components, see #1143. This would be great as an external package!

@mxstbr mxstbr closed this as completed Oct 11, 2017
@gabiseabra
Copy link

If anyone's still interested, I made styled-transition-group, which exports a new styled object as geelen proposed.

@granmoe
Copy link

granmoe commented Feb 21, 2018

I appreciate the conciseness of the proposed APIs of styled-transition-group and styled-components-transition-group, but couldn't this easily be accomplished by just creating a little component that takes styles (as strings or maybe as styled-components.css templates) for the entering/entered/exiting/exited states, and a few other options, and a styled component, and returns a react-transition-group/Transition and just applies the styles to the styled component as the state changes? Something like:

// in some component's render method
const animationStyleProps = {
  entering,
  exiting,
  transition,
  duration
}

return <Animate status={this.state.show} {...animationStyleProps} component={SomeStyledComponent} />

I like the creativity, but it seems like there's a high cost in terms hackiness (reaching into styled-components internals, for example) to get the sole benefit of concise syntax. Plus, we'd have to create editor extensions (or create a PRs for existing extensions) for CSS syntax highlighting within these new "transition" styled components. Am I missing part of the picture here?

@corysimmons
Copy link

@ezsper @gabiseabra Thank you! This is beautiful and makes animations a joy to work with.

@granmoe
Copy link

granmoe commented Mar 18, 2018

I'm throwing my hat in the ring. I've used a slightly different, more minimal approach: https://github.com/granmoe/styled-animate

@corysimmons
Copy link

corysimmons commented Mar 18, 2018

Gonna try to get one of these working with https://github.com/cheapsteak/react-transition-group-plus (Sarah Drasner mentioned this pairs well with GSAP which is exciting), and react-router for cancelable/reversable page transitions 🤤. Will post boilerplate if I get it.

@granmoe btw your lib reminds me a lot of how https://github.com/SamKnows/transform-when handles animation with arrays and such. 👌

@sonaye
Copy link

sonaye commented Apr 14, 2018

I looked into a couple of implementations here and ended up abstracting what I was looking for to something much simpler (doesn't require styled-components).

// animates a child
<Animated>
  <Foo />
</Animated>

// animates a group of children
<Animated items>
  {foos.map(() => <Animated item><Foo /></Animated>)}
</Animated>

Demo & package, thanks for inspiring this work.

@sonaye
Copy link

sonaye commented Apr 14, 2018

I tried to make it play nice with styled-components for a minute, I found it to be tricky since the generated class names are not fixed. Also not sure if the css is attached to each component or if it's optimized.

Let's say that we have:

const Foo = styled.p`color: red;`;
const Bar = styled.p`color: red;`;

@geelen Will styled-components generate a single css class that is attached to both components? since the css is identical here. In other words, are you hashing the css or just generating random class names?

@corysimmons
Copy link

corysimmons commented Apr 14, 2018

@sonaye That's actually really awesome. Will definitely start using that (I'm back on SCSS now).

If you require a fixed class name you could do styled.p.attrs({ className: 'fixed-class' })

@sonaye
Copy link

sonaye commented Apr 16, 2018

@corysimmons I actually didn't know that you can do that, nice. This addresses something I was looking for in this library a while ago (composition of styled-components #932). I've been stubborn about writing css in string templates, but I finally gave it a shot and I kind of like it now, I am gradually moving to use styled-components exclusively.

react-transition-group doesn't require a fixed class name, it requires another prop called classNames that takes values that help mapping the total transition.

I was able to integrate the package with animate.css, adding animations in React is truly a breeze now.

@yss14
Copy link

yss14 commented May 3, 2018

@granmoe Thanks for this package, it works like a charm! :)

@granmoe
Copy link

granmoe commented May 3, 2018

@yss14 Thanks! 😄

I would very much welcome PRs for it if you find that there's anything missing or if anything can be improved--I'm working on a deep learning project in most of my off time currently.

@aperkaz
Copy link

aperkaz commented Jun 16, 2020

Great tip @sonaye ! I applied you tip, and working with animations is so much easier now 🙂

If someone is curious, I pieced together an example of react-transition-group and animate.css at: https://codesandbox.io/s/csstransition-react-n1t10?file=/index.js

Happy codding! 🚀

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

No branches or pull requests