Trying to use ReactCSSTransitionGroup for a Singleton - reactjs

I'd like to move something bottom: +/- 100px.
So that when focused, it slides up. When unfocused, it slides back down.
I've created this React render() :
var component = (
<div key={"trayResponder_" + this.props.trayOpen} >
</div>
);
return(
<ReactCSSTransitionGroup transitionName="tray-responder">
{component}
</ReactCSSTransitionGroup>
);
And then I toggle it's key state, by updating this.props.trayOpen
And then my Less is like this :
.tray-responder-enter {
}
.tray-responder-enter-active {
.animation(slideUp 1s ease infinite )
}
.tray-responder-leave {
}
.tray-responder-leave-active {
.animation(slideDown 1s ease infinite )
}
.keyframes(slideUp;{
0% {transform: translateY(100%);}
50% {transform: translateY(-8%);}
65% {transform: translateY(4%);}
80% {transform: translateY(-4%);}
95% {transform: translateY(2%);}
100% {transform: translateY(0%);}
});
.keyframes(slideDown;{
0% {transform: translateY(-100%);}
50%{transform: translateY(8%);}
65%{transform: translateY(-4%);}
80%{transform: translateY(4%);}
95%{transform: translateY(-2%);}
100% {transform: translateY(0%);}
});
Which adopts from animation.less :
.keyframes(#name; #arguments) {
#-moz-keyframes #name { #arguments(); }
#-webkit-keyframes #name { #arguments(); }
#keyframes #name { #arguments(); }
}
.animation(#arguments) {
-webkit-animation: #arguments;
-moz-animation: #arguments;
animation: #arguments;
}
Unfortunately, this doesn't seem to work. Nothing occurs. No animation. Not really sure why.
Update
The trouble with ReactCSSTransitionGroup is that enter-active and leave-active occur simultaneously. Which doesn't seem to be a problem if you're toggling opacity. But if you're moving things up and down like I am, then you see both at the same time.
As seen here :

As much as I understand, CSS Transition is for enter and leave. You want animation on hover, which can probably be achieved by using :hover selector.
const TransitionDemo = React.createClass({
render : function () {
return(
<div className="demo">
<p>Some Text Here</p>
</div>
);
}
});
ReactDOM.render(<TransitionDemo trayOpen={1}/>, document.getElementById('root'));
//css
.demo {
height : 100px;
position : relative;
}
.demo p {
position : absolute;
bottom : 0px;
transition : all 1s ease;
}
.demo:hover > p{
bottom : 50px;
transition : all 1s ease;
}
See this pen : http://codepen.io/umgupta/pen/dNNLxL

Related

Best way to animate object/image randomly around within a div?

I have an animated gif, which I want to animate slowly and smoothly around. The gif needs to stay with the parent div. Which reactJS libraries would you suggest using for this task? As I guess it cannot be done only using CSS.
You may want to take a look at tutorials like this one:
https://css-tricks.com/bounce-element-around-viewport-in-css/
body {
margin: 0;
}
img, div {
width: 100px;
height: 100px;
}
.x {
animation: x 2.6s linear infinite alternate;
}
.y {
animation: y 0.8s linear infinite alternate;
}
#keyframes x {
100% {
transform: translateX( calc(100vw - 100px) );
}
}
#keyframes y {
100% {
transform: translateY( calc(100vh - 100px) );
}
}
<div class="x">
<img class="y" src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/ef/Stack_Overflow_icon.svg/768px-Stack_Overflow_icon.svg.png" alt="codepen" />
</div>

How to add a smooth sliding transition effect to a react-bootstrap based Column component?

To summarize the problem, I am trying to work through a component that has 2 columns (react-bootstrap Column component). The left container being collapsible and the right always there. On a click of a button, I will toggle show/hide on the left column. It works fine but the behavior is rugged. Whereas, I want to add a transition effect to achieve a smoother slide behavior.
More info...I have a page where I want to display products and filter the products based on different properties such as cost, size, category etc. So, I use a container inside and got 2 columns inside it a row.
Problem: Transition not so smooth...
Something like this in the code below,
import React, { Component } from 'react';
import { ProductsViewFilter } from '../../Controls/ProductsViewFilter/ProductsViewFilter';
import { ProductsView } from '../../Controls/ProductsView/ProductsView';
import { Container, Row, Col, Collapse } from 'react-bootstrap';
import './ProductsViewContainer.css';
export class ProductsViewContainer extends Component {
constructor(props) {
super(props);
this.state = {
filterExpanded: false
}
}
render() {
return (
<Container className='products-view-filter-container'>
<Row>
<Collapse in={this.state.filterExpanded}>
<Col sm={2} className={this.state.filterExpanded ? 'products-view-filter products-view-filter-transition-slide-in' : 'products-view-filter products-view-filter-transition-slide-out'}>
<ProductsViewFilter></ProductsViewFilter>
</Col>
</Collapse>
<Col className='products-view-container-productsview'>
<div className='slider-icon-div' >
<img className='slider-icon' src='/images/icons/slider.svg'
onClick={(e) => { e.preventDefault(); this.setState({ filterExpanded: !this.state.filterExpanded }); }} />
</div>
<ProductsView></ProductsView>
</Col>
</Row>
</Container>);
}
}
.products-view-filter-container
{
max-width: 100% !important;
}
.products-view-filter
{
background-color: wheat;
transform: translateX(-150px);
transition: transform 400ms ease-in;
}
.products-view-filter-transition-enter
{
transform: scale(0.8);
opacity: 0;
}
.products-view-filter-transition-enter-active
{
opacity: 1;
transform: translateX(0);
transition: opacity 300ms, transform 300ms;
}
.products-view-filter-transition-exit
{
opacity: 1;
}
.products-view-filter-transition-exit-active
{
opacity: 0;
transform: scale(0.9);
transition: opacity 300ms, transform 300ms;
}
.products-view-filter-transition-slide-in {
transform: translateX(0);
}
.products-view-filter-transition-slide-out {
transform: translateX(-100%);
}
.products-view-container-productsview
{
background-color: lavender;
}
.slider-icon
{
height: 1.5rem;
}
.slider-icon:hover
{
cursor: pointer;
}
.slider-icon-div
{
margin-top: 15px;
text-align: left;
}
I would like to see the behavior as something like https://codepen.io/bjornholdt/pen/MpXmmL/.
I know this is easily achievable by using bunch of pure divs. But, my desire is to use bootstrap components as it responsive in mobile devices.
Any advice, suggestion as to how to achieve sticking to Col and Row components with a smooth transitions will be really helpful.
This might be too late, but in case anyone else has this issue...
I have not tested this myself, but try what the docs (https://react-bootstrap.github.io/utilities/transitions/) suggest.
...
Collapse#
Add a collapse toggle animation to an element or component.
Smooth animations
If you're noticing choppy animations, and the component that's being collapsed has non-zero margin or padding, try wrapping the contents of your inside a node with no margin or padding, like the in the example below. This will allow the height to be computed properly, so the animation can proceed smoothly.
...

ReactJS: Fade in div and fade out div based on state

So, I am trying to fade in and fade out a set of inputs based on what button the user clicks. I tried using jQuery, but, the div was fading in and fading out at the same speed...
I am using es6 classes and react.
What I want is the user to press a button and the inputs fadeIn. Another button, the inputs fadeOut. I don't mind using jQuery, but I would like to understand how to do this with react.
renderInputs() {
if (this.state.addType === "image") {
return (
<div className="addContainer">
<input type="text" className="form-control" />
</div>
)
} else {
return (
other inputs
)
}
}
render() {
return (
<CSSTransitionGroup
transitionName="fadeInput"
transitionEnterTimeout={500}
transitionLeaveTimeout={300}>
{this.renderInputs()} // this doesn't work but I want this content to be conditional.
</CSSTransitionGroup>
)
}
// SCSS
.fadeInput-enter {
opacity: 0.01;
}
.fadeInput-enter.fadeInput-enter-active {
opacity: 1;
transition: opacity 500ms ease-in;
}
.fadeInput-leave {
opacity: 1;
}
.fadeInput-leave.fadeInput-leave-active {
opacity: 0.01;
transition: opacity 300ms ease-in;
}
Just use a conditional class and CSS.
Have a state variable like visible.
this.state = {
visible:false
}
And for the other inputs do something like
<input className={this.state.visible?'fadeIn':'fadeOut'} />
So depending upon the state.visible the input will have a class of either fadeIn or fadeOut.
And then just use simple CSS
.fadeOut{
opacity:0;
width:0;
height:0;
transition: width 0.5s 0.5s, height 0.5s 0.5s, opacity 0.5s;
}
.fadeIn{
opacity:1;
width:100px;
height:100px;
transition: width 0.5s, height 0.5s, opacity 0.5s 0.5s;
}
So every time the state.visible changes the class changes and the transition takes place. The transition property in CSS is basically all the transitions separated by commas. Within the transition the first argument is the property to be modified (say height, width etc), second is transition-duration that is the time taken for the transition and third(optional) is transition-delay ie how much time after the transition has been initiated does the transition for the particular property take place. So when this.state.visible becomes true the .fadeIn class is attached to the object. The transition has height and width taking 0.5s each so that will take 0.5s to grow and after it is finished the opacity transition (which has a delay of 0.5s) will trigger and take a further 0.5s to get opacity 1. For the hiding it's the reverse.
Remember to have the OnClick event on the button handle the changing of this.state.visible.
You could also achieve this with CSSTransitionGroup
const Example = ({items, removeItemHandler}) => {
return (
<div>
<CSSTransitionGroup transitionName="fadeInput"
transitionEnterTimeout={500}
transitionLeaveTimeout={300}>
{this.renderInputs().map(function(input) {
return (
<div key={input.id} className="my-item" onClick={removeItemHandler}>
{item.name}
</div>
);
})}
</ReactCSSTransitionGroup>
</div>
);
};
When working with React, sometimes you want to animate a component directly after it has been mounted, or directly prior to it being unmounted.
Like in your example, Let’s say you map over an array of objects and render a list in your application. Now let’s say you want to add animations to fade-in new items that have been added to the array or fade-out items as they are removed from the array.
The CSSTransitionGroup component takes in transitionEnterTimeout and transitionLeaveTimeout as props. What these values represent are the duration in milliseconds of your enter and leave transitions.
A simple way to achieve this with styled components...
const Popup = styled.div`
width: 200px;
height: 200px;
transition: opacity 0.5s;
opacity: ${({ showPopup }) => (showPopup ? '1' : '0')};
`;
<Popup showPopup={showPopup}>
{...}
</Popup>

React styled-components fade in/fade out

I am trying to build a React component to handle fading in and fading out. In the following code, if I pass out as a prop to the component, it is disaplayed as hidden before animating out. I'm trying to have it fade in by default, then fade out when I pass in the out prop. Anyone see a solution to this problem?
import React from 'react';
import styled, { keyframes } from 'styled-components';
const fadeIn = keyframes`
from {
transform: scale(.25);
opacity: 0;
}
to {
transform: scale(1);
opacity: 1;
}
`;
const fadeOut = keyframes`
from {
transform: scale(1);
opacity: 0;
}
to {
transform: scale(.25);
opacity: 1;
}
`;
const Fade = styled.div`
${props => props.out ?
`display: none;`
: `display: inline-block;`
}
animation: ${props => props.out ? fadeOut : fadeIn} 1s linear infinite;
`;
function App() {
return (
<div>
<Fade><💅test></Fade>
</div>
);
}
export default App;
WebpackBin running example
The issue with your code is that you're setting the display property to none when props.out is true. That's why you're not seeing any animation, because before that can even start you've already hidden the component!
The way to do a fade out animation is to use the visibility property instead and transition that for the same amount of time as the animation takes. (see this old SO answer)
Something like this should solve your issues:
const Fade = styled.default.div`
display: inline-block;
visibility: ${props => props.out ? 'hidden' : 'visible'};
animation: ${props => props.out ? fadeOut : fadeIn} 1s linear;
transition: visibility 1s linear;
`;
const fadeIn = styled.keyframes`
from {
transform: scale(.25);
opacity: 0;
}
to {
transform: scale(1);
opacity: 1;
}
`;
const fadeOut = styled.keyframes`
from {
transform: scale(1);
opacity: 1;
}
to {
transform: scale(.25);
opacity: 0;
}
`;
const Fade = styled.default.div`
display: inline-block;
visibility: ${props => props.out ? 'hidden' : 'visible'};
animation: ${props => props.out ? fadeOut : fadeIn} 1s linear;
transition: visibility 1s linear;
`;
class App extends React.Component {
constructor() {
super()
this.state = {
visible: true,
}
}
componentDidMount() {
setTimeout(() => {
this.setState({
visible: false,
})
}, 1000)
}
render() {
return (
<div>
<Fade out={!this.state.visible}><💅test></Fade>
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<script src="https://unpkg.com/styled-components/dist/styled-components.min.js"></script>
<div id="root" />
Note: Your fadeOut animation also went from 0 to 1 opacity, instead of the other way around. I've fixed that in the snippet too.

How to add page transitions to React without using the router?

I tried to add page transitions to my app using ReactCSSTransitionGroup but it did not work. For some pages it worked but for some it did not. Many examples out there show how to do it with the React router. But since I use Meteor, I use a different router (FlowRouter).
Here's my render method :
render() {
return (
<div>
{this.props.content()}
</div>
);
}
Here's how I tried to add transitions :
<ReactCSSTransitionGroup
transitionName="pageTransition"
transitionEnterTimeout={500}
transitionLeaveTimeout={300}
transitionAppear={true}
transitionAppearTimeout={500}
>
{/* Content */}
{React.cloneElement(this.props.content(), {
key: uuid.v1(),
})}
</ReactCSSTransitionGroup>
The css :
//Page transition
.pageTransition-enter {
opacity: 0.01;
}
.pageTransition-enter.pageTransition-enter-active {
animation: fadeIn 1s ease-in;
}
.animation-leave {
opacity: 1;
}
.pageTransition-leave.pageTransition-leave-active {
animation: fadeIn 3s ease-in;
}
.pageTransition-appear {
opacity: 0.01;
}
.pageTransition-appear.pageTransition-appear-active {
animation: opacity 5s ease-in;
}
Any idea how to make this work?
I figured it out! Your CSS animations are trying to use fadeIn, but that's not a CSS property. You need to change it to opacity. Like so:
//Page transition
.pageTransition-enter {
opacity: 0.01;
}
.pageTransition-enter.pageTransition-enter-active {
animation: opacity 1s ease-in;
}
.animation-leave {
opacity: 1;
}
.pageTransition-leave.pageTransition-leave-active {
animation: opacity 3s ease-in;
}
.pageTransition-appear {
opacity: 0.01;
}
.pageTransition-appear.pageTransition-appear-active {
animation: opacity 5s ease-in;
}
try defining your inner component before return call:
render() {
const clonedElement = <div>{this.props.content()}</div>;
return (
<ReactCSSTransitionGroup transitionName="pageTransition" transitionEnterTimeout={500} transitionLeaveTimeout={300} transitionAppear={true} transitionAppearTimeout={500}>
{clonedElement}
</ReactCSSTransitionGroup>
);
}

Resources