exit animation will only work if start animation is in progress - smoothstate.js

I have this problem where the animation will only exit if the start animation is still in progress. Once the start animation finishes and I click another link it still adds the reverse class but only show a white page and the animation will not exit.
Here is the smoothstate call:
$(function(){
'use-strict';
var options = {
anchors: 'a',
prefetch: true,
blacklist: '.no-smoothState',
debug: true,
cacheLength: 2,
onStart: {
duration: 1000,
render: function($container) {
$container.addClass('is-exiting');
smoothState.restartCSSAnimations();
}
},
onReady: {
duration: 1000,
render: function($container, $newContent) {
$container.removeClass('is-exiting');
$container.html($newContent);
}
},
onAfter: function($container, $newContent) {
}
},
smoothState = $('#wrapper').smoothState(options).data('smoothState');
});
The HTML:
<div id="wrapper">
<div id="portfolio" class="portfolio">
<header>...</header>
<main id="content">
<section>
<h2>...</h2>
</section>
</main>
</div>
</div><!-- // wrapper -->
The CSS:
#wrapper #content {
animation-duration: 1s;
transition-timing-function: ease;
animation-fill-mode: forwards;
}
#wrapper #content {
animation-name: fadeInUp;
}
#wrapper.is-exiting #content {
animation-direction: alternate-reverse;
}
#keyframes fadeInUp {
0% {
opacity: 0;
transform: translateY(60px);
}
100% {
opacity: 1;
transform: translateY(0);
}
}

Got it to work. If you use classes instead of ID's when targeting the animation it will start the exit animation.

Related

simple css animation not working on dynamic reactjs element

Check the snippet at codepen http://codepen.io/anon/pen/EZJjNO
Click on Add button, it will add another item but its appearing immediately without any fade effect.
JS:
class App extends React.Component {
constructor(props) {
super(props);
this.addItem = this.addItem.bind(this);
this.state = {
items: [1,2,3]
}
}
addItem() {
var items = this.state.items;
items.push(4);
this.setState({
items: items
})
}
render() {
return (
<div className="App">
{
this.state.items.map(function(i) {
return <div className="item fade">Testing</div>
})
}
<button onClick={this.addItem}>Add</button>
</div>
);
}
}
React.render(<App />, document.body);
CSS:
.App {
background-color: rgba(0,0,0, 0.5);
text-align: center;
height: 100vh;
}
div.item {
border: 1px solid #ccc;
padding: 10px;
background: #123456;
color: #fff;
opacity: 0;
transition: all 0.4s ease-out;
}
.fade {
opacity: 1 !important;
}
Since the fade class is added by default, you don't get the transition effect. If you open your browser's developer tools and remove the class, you'll see it fade away nicely.
There's a few ways to get what you want, but I'd just use a keyframe CSS animation like so:
.fade {
animation: 0.4s ease-out fadeIn 1;
}
#keyframes fadeIn {
0% {
opacity: 0;
visibility: hidden;
}
100% {
opacity: 1;
visibility: visible;
}
}
Here's a fork of your code pen showing how it works :)

React CSS Transitions

I'm learning React CSS Transitions. So I decided to make a sliding sidebar navigation. The sidebar slides in from right just fine. But I can't get leave animations working. I'm not sure what's going on.
The jsx:
render: function() {
return(
<div className="_Sidebar">
<div className="top">
<i
className="menuIcon fa fa-bars"
onClick={() => this.handleClick()}>
</i>
<UserName />
</div>
{this.state.show ?
<ReactCSSTransitionGroup
transitionName="example"
transitionAppear={true}
transitionLeave={true} >
<div key={"slidebar"} className="sidebar">
{this.handleItems()}
</div>
</ReactCSSTransitionGroup>
: null}
</div>
);
}
And the css:
.example-appear {
left: -230px;
transition: left .9s ease-in;
}
.example-appear.example-appear-active {
left: 0px;
}
.example-leave {
left: 0px;
transition: left .9s ease-out;
}
.example-leave.example-leave-active {
left: -230px;
}
really I tried in your code there is a thing not right in putting ReactCSSTransitionGroup tag, so I attached my code , its woke correct, you can use it directly and put your data,
import React from 'react';
import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
var Test = React.createClass({
getInitialState: function () {
return { active: true };
},
onToggle: function () {
this.setState({active: !this.state.active});
},
render: function() {
return (
<div>
<ReactCSSTransitionGroup
transitionName="fade"
transitionEnterTimeout={500}
transitionLeaveTimeout={300}>
{!this.state.active && ( <h2> Test Asmaa Almadhoun </h2>)}
</ReactCSSTransitionGroup>
<div className="chatBTN" onClick={this.onToggle}>
<img src="../src/contents/images/svg/chat.svg"/>
</div>
</div>
);
}
});
export default Test;
CSS File
.chatBar{
position: fixed;
height: 320px;
z-index: 0;
right: 0;
top: 40px;
width: 150px;
text-align: center;
display: block;
transform: translateY(-40px);
}
.fade-enter {
transform: translateY(-88%);
}
.fade-enter-active {
top: 0;
transform:translateY(-40px);
transition: .5s ease-in all;
}
.fade-leave {
transform: translateY(-40px);
}
.fade-leave-active {
transform: translateY(-88%);
transition: 0.3s ease-out all;
}

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>
);
}

$timeout service not updating angular controller from directive

"use strict";
angular.module("appBanner", [])
.controller('bannerCtrl', function($scope) {
$scope.slides = ["auto", "boatowners", "commercial"];
$scope.currentIndex = 0;
$scope.setCurrentSlideIndex = function (index) {
$scope.currentIndex = index;
$scope.currentSlideIndex = $scope.slides[$scope.currentIndex];
}
$scope.isCurrentSlideIndex = function (index) {
return $scope.currentIndex === index;
};
$scope.prevSlide = function () {
$scope.currentIndex = ($scope.currentIndex > 0) ? --$scope.currentIndex : $scope.slides.length - 1;
$scope.setCurrentSlideIndex($scope.currentIndex);
};
$scope.nextSlide = function () {
$scope.currentIndex = ($scope.currentIndex < $scope.slides.length - 1) ? ++$scope.currentIndex : 0;
$scope.setCurrentSlideIndex($scope.currentIndex);
};
})
.directive('banner', function($timeout) {
return {
link: function postLink(scope, element, attrs) {
var progressBar = angular.element(".progress");
var bannerNav = angular.element(".bannerNav");
var navCircle = angular.element(".bannerNav.navCircle");
var imgSlides = angular.element(".imgSlide");
var slideTime = 1.5;
TweenMax.set(imgSlides, {
autoAlpha: 0,
display: "none"
});
TweenMax.set(progressBar, {
autoAlpha: 0
});
var tlMaster = initMasterTimeline(imgSlides, progressBar, slideTime);
scope.getWidth = function() {
return $(element).width();
};
scope.play = function(newIndexValue) {
tlMaster.play(newIndexValue);
};
scope.$watch('slideshowHover', function(newValue) {
if (newValue === true) TweenMax.to(bannerNav, 0.5, {
autoAlpha: 0.85
})
else TweenMax.to(bannerNav, 0.5, {
autoAlpha: 0.25
})
});
scope.$watch('currentSlideIndex', function(newIndexValue) {
scope.play(newIndexValue);
});
scope.$watch(scope.getWidth, function(width) {
element.css('height', width * 0.4);
});
function updateCurrentIndex(index) {
$timeout(function() {
scope.setCurrentSlideIndex(index);
});
}
function setProgress(timeline, progressBar) {
TweenMax.set(progressBar, {
scaleX: timeline.progress()
});
}
function initMasterTimeline(imgSlides, progressBar, slideTime) {
var tlAuto = initAutoTimeline(imgSlides, progressBar, slideTime);
var tlBoatowners = initBoatownersTimeline(imgSlides, progressBar, slideTime);
var tlCommercial = initCommercialTimeline(imgSlides, progressBar, slideTime);
var tlMaster = new TimelineMax({
repeat: -1
});
tlMaster.set(progressBar, {
scaleX: 0,
transformOrigin: "left"
})
.add(tlAuto, "auto")
.add(tlBoatowners, "boatowners")
.add(tlCommercial, "commercial");
return tlMaster;
}
function initAutoTimeline(imgSlides, progressBar, slideTime) {
var stayTime = 10; //for now, can make each timeline as long as you want later
var tlAuto = new TimelineLite({
onUpdate: setProgress,
onUpdateParams: ["{self}", progressBar]
});
var autoNavCircle = $(".navCircle")[0];
tlAuto.set(imgSlides[0], {
display: "block"
})
.to(progressBar, slideTime, {
autoAlpha: 1
}, 0)
.to(imgSlides[0], slideTime, {
autoAlpha: 1
}, 0)
.to(imgSlides[0], slideTime, {
autoAlpha: 0
}, stayTime)
.to(progressBar, slideTime, {
autoAlpha: 0
}, stayTime)
.set(imgSlides[0], {
display: "none",
onComplete: updateCurrentIndex(1)
})
return tlAuto;
}
function initBoatownersTimeline(imgSlides, progressBar, slideTime) {
var stayTime = 10; //for now, can make each timeline as long as you want later
var tlBoatowners = new TimelineLite({
onUpdate: setProgress,
onUpdateParams: ["{self}", progressBar]
});
var boatownersNavCircle = $(".navCircle")[1];
tlBoatowners.set(imgSlides[1], {
display: "block"
})
.to(progressBar, slideTime, {
autoAlpha: 1
}, 0)
.to(imgSlides[1], slideTime, {
autoAlpha: 1
}, 0)
.to(imgSlides[1], slideTime, {
autoAlpha: 0
}, stayTime)
.to(progressBar, slideTime, {
autoAlpha: 0
}, stayTime)
.set(imgSlides[1], {
display: "none",
onComplete: updateCurrentIndex(2)
});
return tlBoatowners;
}
function initCommercialTimeline(imgSlides, progressBar, slideTime) {
var stayTime = 10; //for now, can make each timeline as long as you want later
var tlCommercial = new TimelineLite({
onUpdate: setProgress,
onUpdateParams: ["{self}", progressBar]
});
var commercialNavCircle = $(".navCircle")[2];
tlCommercial.set(imgSlides[2], {
display: "block"
})
.to(progressBar, slideTime, {
autoAlpha: 1
}, 0)
.to(imgSlides[2], slideTime, {
autoAlpha: 1
}, 0)
.to(imgSlides[2], slideTime, {
autoAlpha: 0
}, stayTime)
.to(progressBar, slideTime, {
autoAlpha: 0
}, stayTime)
.set(imgSlides[2], {
display: "none",
onComplete: updateCurrentIndex(0)
});
return tlCommercial;
}
}
}
})
#slideshow{
position: relative;
}
.imgSlide{
position: absolute;
width: 100%;
}
.progress{
position: absolute;
width: 100%;
height:3px;
background: #F1F1F1;
z-index: 5;
}
.navCircleContainer {
position: absolute;
display: flex;
justify-content: space-between;
padding: 5px;
bottom: 2.5px;
left: 12.5%;
width: 75%;
height: auto;
}
.navCircle {
opacity: 0.25;
}
div.navCircle {
position: relative;
border-radius: 100%;
background:#F1F1F1;
}
.navCircle.active {
opacity:1;
}
#media only screen and (min-width: 768px) {
div.navCircle{
width: 30px;
height: 30px;
}
}
#media only screen and (max-width: 767px) {
div.navCircle{
width: 15px;
height: 15px;
}
}
.navCircle span {
position: absolute;
color:#F1F1F1;
font-weight: bold;
left: 50%;
-moz-transform: translateX(-50%);
-webkit-transform: translateX(-50%);
-ms-transform: translateX(-50%);
-o-transform: translateX(-50%);
transform: translateX(-50%);
}
#media only screen and (min-width: 768px) {
.navCircle span {
bottom: 30px;
}
}
#media only screen and (max-width: 767px) {
.navCircle span {
bottom: 20px;
}
}
.navArrow {
position: absolute;
top: 50%;
color:#F1F1F1;
-moz-transform: translateY(-50%);
-webkit-transform: translateY(-50%);
-ms-transform: translateY(-50%);
-o-transform: translateY(-50%);
transform: translateY(-50%);
}
#navArrowLeft {
left: 0%;
}
#navArrowRight {
right: 0%;
}
img {
width: 100%;
height: auto;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.5.0/css/font-awesome.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular-animate.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/gsap/1.15.0/TweenMax.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.10/angular-ui-router.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.18.2/jquery.gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.1/jquery.min.js"></script>
<div ng-app="appBanner" ng-controller="bannerCtrl" banner id="slideshow" ng-mouseover="slideshowHover = true" ng-mouseleave="slideshowHover = false" ng-init="slideshowHover = false">
<!-- green field with lake -->
<img class="imgSlide" src="http://cdn.morguefile.com/imageData/public/files/i/imma/08/l/14089545069hw66.jpg" >
<!-- waterfall -->
<img class="imgSlide" src="http://cdn.morguefile.com/imageData/public/files/i/imma/preview/fldr_2012_09_09/file3231347173227.jpg" >
<!-- red sunset -->
<img class="imgSlide" src="http://cdn.morguefile.com/imageData/public/files/i/imma/preview/fldr_2012_07_22/file541342984669.jpg" >
<div class="progress"></div>
<div id="navArrowLeft" class="navArrow bannerNav" ng-click="prevSlide()">
<div class="hidden-xs">
<i class="fa fa-angle-double-left fa-5x"></i>
</div>
<div class="hidden-sm hidden-md hidden-lg">
<i class="fa fa-angle-double-left fa-2x"></i>
</div>
</div>
<div id="navArrowRight" class="navArrow bannerNav" ng-click="nextSlide()">
<div class="hidden-xs">
<i class="fa fa-angle-double-right fa-5x"></i>
</div>
<div class="hidden-sm hidden-md hidden-lg">
<i class="fa fa-angle-double-right fa-2x"></i>
</div>
</div>
<div class="navCircleContainer">
<div class="navCircle bannerNav" ng-active="isCurrentSlideIndex === 0" ng-mouseover="navCircleAutoHover = true" ng-mouseleave="navCircleAutoHover = false" ng-init="navCircleAutoHover = false" ng-click="play('auto')"><span class="bannerNav fade" ng-show="navCircleAutoHover === true">Lake</span></div>
<div class="navCircle bannerNav" ng-active="isCurrentSlideIndex === 1" ng-mouseover="navCircleBoatownersHover = true" ng-mouseleave="navCircleBoatownersHover = false" ng-init="navCircleBoatownersHover = false" ng-click="play('boatowners')"><span class="bannerNav fade" ng-show="navCircleBoatownersHover === true">Waterfall</span></div>
<div class="navCircle bannerNav" ng-active="isCurrentSlideIndex === 2" ng-mouseover="navCircleCommercialHover = true" ng-mouseleave="navCircleCommercialHover = false" ng-init="navCircleCommercialHover = false" ng-click="play('commercial')"><span class="bannerNav fade" ng-show="navCircleCommercialHover === true"> Sunset</span></div>
</div>
</div>
Working Codepen Link
I had some trouble getting this to work here in stackoverflow, but the working codepen link is provided. My problem is that the updateCurrentIndex(nextIndex) that works in conjunction with $timeout and happens onComplete at the end of each child timeline does not seem to communicate the normal increments of the index when it plays.
So, this works fine if you click next, previous, or any of the direct go to circle buttons at the bottom before the timeline has time to go to next slide (index incremented outside user control). However, when the timeline plays next slide, the index in the controller is not aware of this change and it becomes out of sync. I have been pointed towards the $timeout service as a way to fix this, but it still is not working. Any help greatly appreciated.
There is quite a bit of code to sort out in demo but you have two invalid function references like:
onComplete: updateCurrentIndex(2)
First these are hard coded values and second they will be invoked immediately not when onComplete fires as you are expecting:
To pass a function as reference you can't use () so correct way would be:
onComplete: updateCurrentIndex
But since you need to pass parameters you would need something like:
onComplete: function(arg1,arg2){ // not sure what arguments are available
var newIndex = // I'm not sure how to get index in this event
updateCurrentIndex(newIndex);
}
I just figured it out. My problem was the following: onComplete:updateCurrentIndex, onCompleteParams:[nextIndex]
I was passing it this: onComplete: updateCurrentIndex(2)
and yes it was executing immediately. it works now.

React Transition group not firing

i tried to create a simple transition with react transition group, but i can't get it to work- transitions aren't working.
i did used a unique key.
for the example i just did a simple 2 image fade in fade out component:
var ReactCSSTransitionGroup = React.addons.TransitionGroup;
var Image = React.createClass({
getInitialState: function () {
return ({imglink: 'http://belaumi.com/wp-content/uploads/2014/11/3D-Animated-Frog-Image.jpg', status: 1})
},
update: function () {
console.log(this);
if (this.state.status==1)
{
this.setState({ imglink: 'http://www.codefuture.co.uk/projects/imagehost/demo/di/KXY1/Image-b%C3%A9b%C3%A9-facebook-8.jpg', status:2})
} else {
this.setState({ imglink: 'http://belaumi.com/wp-content/uploads/2014/11/3D-Animated-Frog-Image.jpg', status:1})
}
} ,
render: function () {
return (
<div>
<div className='container'>
<button onClick={this.update.bind(this)}>Click</button>
<ReactCSSTransitionGroup transitionName="example">
<img key={this.state.status} src={this.state.imglink}/>
</ReactCSSTransitionGroup>
</div>
</div>
);
}
});
React.render(
<div>
<Image/>
</div>,
document.getElementById('reactbody')
)
</script>
i've also included proper css:
.example-enter {
opacity: 0.01;
transition: opacity .5s ease-in;
-webkit-transition: opacity .5s ease-in;
}
.example-enter.example-enter-active {
opacity: 1;
}
.example-leave {
opacity: 1;
transition: opacity .5s ease-in;
-webkit-transition: opacity .5s ease-in;
}
.example-leave.example-leave-active {
opacity: 0.01;
}
any idea why this is not working? the image does switch, but no fade..
thanks!
The addons name is CSSTransitionGroup:
var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
instead of
var ReactCSSTransitionGroup = React.addons.TransitionGroup;
(Notice the CSSTransitionGroup)
Working jsfiddle: http://jsfiddle.net/wvt30ocx/

Resources