How to make slideIn AND slideOut with styled-components with react-animations - css

I'm working on building a component that displays none or block depending on it's isActive prop.
I've managed to make it slideInDown using react-animations with styled-components like this.
import styled, { keyframes } from 'styled-components';
import { ifProp } from 'styled-tools';
import { slideInDown } from 'react-animations';
const slideInAnimation = keyframes`${slideInDown}`;
const MyComponent = styled.div`
animation: 0.4s ${slideInAnimation};
display: ${ifProp('isActive', 'block', 'none')};
`;
I need to make it slideOutUp now. However, I'm not sure how to implement both slideInDown and slideOutUp animations together.
How would I accomplish that?
Note: that works. But I don't know how to make it both slide in and out. I tried something like this below but that didn't work.
import styled, { keyframes } from 'styled-components';
import { ifProp } from 'styled-tools';
import { slideInDown, slideOutUp } from 'react-animations';
const slideInAnimation = keyframes`${slideInDown}`;
const slideOutAnimation = keyframes`${slideOutUp}`;
const MyComponent = styled.div`
animation: 0.4s ${slideInAnimation}, 0.4s ${slideOutAnimation};
display: ${ifProp('isActive', 'block', 'none')};
`;

I went through the react-animations library, what I figured out is slideOutUp sets visibility: 'hidden.'
const slideOutUp: Animation = {
from: {
transform: translate3d(0, 0, 0)
},
to: {
visibility: 'hidden',
transform: translate3d(0, '-100%', 0)
}
};
You can use animation-fill-mode: forwards, which helps in retaining the style after the animation ends.
You can do something like this (it works):
const MyComponent = styled.div`
animation: ${ifProp(
"isActive",
`0.4s ${slideInAnimation}`,
`0.4s ${slideOutAnimation} forwards`
)};
`;
Here is the working example, for testing purpose onClick event I am setting {isActive: false}
https://codesandbox.io/s/949ql6p6no

Display does not animate. You need to use opacity for toggling (1 to 0 and vice versa) and animation.
const myComponent = styled.div`
animation: 0.4s ${slideInAnimation};
opacity: ${ifProp('isActive', 1, 0)};
`;
Considering that your code is working like you told me, you can use the attribute infinte at animation:
animation: 0.4s ${slideInAnimation} infinite;
I guess that it solves your problem.

Related

How to apply animation with changing text?

I'm trying to apply animation: smooth disappearing old text and smooth appearing the new one.
Now I created it with useEffect hooks and with inner Transition: onExited function
Furthermore I have not only title value, and my solution seemed to me the duct tape.
const [toggle, setToggle] = useState(true)
const [exited, setExited] = useState(false)
const [title, setTitle] = useState(service.title) //default value
useEffect(() => {
setExited(false) //set default value
setToggle(false)
}, [service]) //unmount node with old text (toggle this hook with changing another **service**)
useEffect(() => {
setToggle(true)
setTitle(service.title)
}, [exited]) //appear after old text unmounted
Node:
<Transition
in={toggle} timeout={500}
mountOnEnter unmountOnExit
onExited={() => setExited(true)}
>
{ state =>
<div className={classes['Services__card-categories-title'] + ' ' + classes[state]}>
{title}
</div>
}
</Transition>
Styles:
.entering{
animation: appearing .5s linear;
}
.exiting{
animation: appearing .5s linear reverse;
}
#keyframes appearing {
0%{
opacity: 0;
}
100%{
opacity: 1;
}
}
How to make it universal using react-transition-group library functionality ?
P.S. One more trouble is transition triggering not depends on single value, if any value is changed -> transition will triggered on every element

Styled-components, SVG not animating

I use styled-components alongside React and I have such component:
import styled, { keyframes } from 'styled-components'
import { ReactComponent as SpinnerIcon } from './spinner.svg'
const rotate = keyframes`
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
`
const Spinner = styled(SpinnerIcon)`
margin-top: 50px;
animation: ${rotate} 2s ease-in infinite;
`
export default Spinner
When I use this component like this:
<Spinner width='50px' height='50px' />
I see this component but it's not animating. What's wrong?
Try this:
const Spinner = styled.img.attrs({
src: SpinnerIcon,
})`
margin-top: 50px;
animation: ${rotate} 2s ease-in infinite;
if this doesn't work for you please share your svg file too. Also you probably need use linear function instead of ease-in
`

React CSSTransition Issues

I am trying to display header one in the beginning and then when clicked on, fade in the second header. However they both are showing up in beginning. My understanding is that the in prop is what controls when the children of get rendered. But for some reason they are being rendered in beginning when showTwo is false. Any help would be much appreciated.
Component
import React, { useState } from "react";
import { CSSTransition } from "react-transition-group";
import "./Intro.css";
function Intro() {
const [showOne, setShowOne] = useState(true);
const [showTwo, setShowTwo] = useState(false);
return (
<>
{showOne && <h1 onClick={() => setShowTwo(true)}>One!</h1>}
<CSSTransition
in={showTwo}
timeout={750}
onEnter={() => setShowOne(false)}
classNames="creation"
>
<h2>Two!</h2>
</CSSTransition>
</>
);
}
export default Intro;
CSS
.creation-enter {
opacity: 0;
}
.creation-enter-active {
opacity: 1;
transition: opacity 700ms;
}
.creation-exit {
opacity: 1;
}
.creation-exit-active {
opacity: 0;
transition: opacity 700ms;
}
I realized that I was missing the prop unmountOnExit and misunderstanding what the in prop is for.
If others stumble upon this with similar issues, in is used to determine when the *-enter, *-enter-active, ... are added as classes.

CSS rotation problem found when execute it in edge

I wrote some pieces of codes in angular about rotating an icon by pressing a toggle button in angular.
When I run it in chrome everything is OK but in Edge rotation process works properly but final rotation status is 180 degree reverse.
Here is my snippets:
my .ts file:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-menutest',
templateUrl: './menutest.component.html',
styleUrls: ['./menutest.component.scss']
})
export class MenutestComponent implements OnInit {
public classChangesRotation: {[key: string]: string} = {};
public expandeds: {[key: string]: boolean} = {};
private zero: string;
constructor() {
this.zero = 'zero';
this.expandeds[this.zero] = true;
this.classChangesRotation[this.zero] = 'rotate-expanded';
}
expansion_click(divName: string) {
this.expandeds[divName] = !this.expandeds[divName];
if (this.expandeds[divName]) {
this.classChangesRotation[divName] = 'rotate-expanded';
} else {
this.classChangesRotation[divName] = 'rotate-collapsed';
}
}
}
my html file:
<button mat-raised-button (click)="expansion_click('zero')">
Expand and Collapse
<mat-icon [ngClass]="classChangesRotation['zero']">
chevron_left
</mat-icon>
</button>
and my scss file contains :
.rotate-expanded {
-webkit-transform: rotate(90deg);
transform: rotate(90deg);
transition: -webkit-transform 150ms;
transition: transform 150ms;
transition: transform 150ms,-webkit-transform 150ms;
transition-timing-function: ease-in-out;
}
.rotate-collapsed {
-webkit-transform: rotate(0);
transform: rotate(0);
transition: -webkit-transform 150ms;
transition: transform 150ms;
transition: transform 150ms,-webkit-transform 150ms;
transition-timing-function: ease-in-out;
}
As I mentioned above when I run these codes in chrome everything is OK and normal but in Edge the animation process is fine but final rotation differs 180 degrees!
Do you have any idea?
Thank you for your attentions.
Pay attention please:
You should know that direction of this code is right to left and result in LTR direction is OK but the problem is in RTL direction. I understand it right now and added it to my question.

CSSTransitionGroup doesn't fade in

I am quite new to react and I am trying to build a react app. I want a login box to fade in on the page when the login in the navbar is clicked. In my App.js I set up the CSSTransitionGroup like this:
<CSSTransitionGroup
transitionEnterTimeout={500}
transitionLeaveTimeout={500}
transitionAppear={true}
transitionAppearTimeout={500}
transitionName="fade">
{loginPopup}
</CSSTransitionGroup>
The login popup is shown based on state:
let loginPopup;
if (display_login) {
loginPopup = (<LoginPopup key={1} />)
}
Now the css I use for the transition looks like this:
//fade
.fade-appear {
opacity: 0.01;
}
.fade-appear-active {
opacity: 1;
transition: opacity 300ms ease-in;
}
.fade-leave {
opacity: 1;
}
.fade-leave-active {
opacity: 0.01;
transition: opacity 300ms ease-in;
}
My problem is...that the fadeout works as intended, but the fadein does not work. It just pops up (no transition).
I also tried using .fade-enter - But I figured that enter was wrong as the LoginPopup component is spawned based on state.
Any ideas why the fade in don't work?
Edit:
This is the gist of the code: https://gist.github.com/xenoxsis/6345eb6897aedf228662ffaf64f65053

Resources