Skip to content

Commit

Permalink
Merge pull request #13 from myarcane/animation-fixes
Browse files Browse the repository at this point in the history
Support transitionEnterTimeout & transitionLeaveTimeout
  • Loading branch information
developit authored Jun 20, 2017
2 parents 7bfbe75 + 663cd4e commit 810f9f2
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 12 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
"mocha": "^2.4.5",
"npm-run-all": "^2.3.0",
"phantomjs-prebuilt": "^2.1.5",
"preact": "^6.0.2",
"preact": "^8.1.0",
"pretty-bytes-cli": "^1.0.0",
"rollup": "^0.34.1",
"rollup-plugin-babel": "^2.4.0",
Expand Down
8 changes: 5 additions & 3 deletions src/CSSTransitionGroup.js
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ export class CSSTransitionGroup extends Component {
}

renderChild = child => {
let { transitionName, transitionEnter, transitionLeave } = this.props,
let { transitionName, transitionEnter, transitionLeave, transitionEnterTimeout, transitionLeaveTimeout } = this.props,
key = getKey(child);
return (
<CSSTransitionGroupChild
Expand All @@ -191,13 +191,15 @@ export class CSSTransitionGroup extends Component {
}}
name={transitionName}
enter={transitionEnter}
leave={transitionLeave}>
leave={transitionLeave}
enterTimeout={transitionEnterTimeout}
leaveTimeout={transitionLeaveTimeout}>
{child}
</CSSTransitionGroupChild>
);
};

render({ component:Component, transitionName, transitionEnter, transitionLeave, children:c, ...props }, { children }) {
render({ component:Component, transitionName, transitionEnter, transitionLeave, transitionEnterTimeout, transitionLeaveTimeout, children:c, ...props }, { children }) {
return (
<Component {...props}>
{ filterNullChildren(children).map(this.renderChild) }
Expand Down
27 changes: 19 additions & 8 deletions src/CSSTransitionGroupChild.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@ import { addEndEventListener, removeEndEventListener } from './TransitionEvents'
const TICK = 17;

export class CSSTransitionGroupChild extends Component {
transition(animationType, finishCallback) {
let node = getComponentBase(this),
className = this.props.name[animationType] || this.props.name + '-' + animationType,
activeClassName = this.props.name[animationType + 'Active'] || className + '-active';
transition(animationType, finishCallback, timeout) {
let node = getComponentBase(this);

let className = this.props.name[animationType] || this.props.name + '-' + animationType;
let activeClassName = this.props.name[animationType + 'Active'] || className + '-active';
let timer = null;

if (this.endListener) {
this.endListener();
Expand All @@ -31,9 +33,9 @@ export class CSSTransitionGroupChild extends Component {
this.endListener = (e) => {
if (e && e.target!==node) return;

clearTimeout(timer);
removeClass(node, className);
removeClass(node, activeClassName);

removeEndEventListener(node, this.endListener);
this.endListener = null;

Expand All @@ -44,7 +46,12 @@ export class CSSTransitionGroupChild extends Component {
}
};

addEndEventListener(node, this.endListener);
if (timeout) {
timer = setTimeout(this.endListener, timeout);
this.transitionTimeouts.push(timer);
} else {
addEndEventListener(node, this.endListener);
}

addClass(node, className);

Expand Down Expand Up @@ -81,17 +88,21 @@ export class CSSTransitionGroupChild extends Component {

componentWillMount() {
this.classNameQueue = [];
this.transitionTimeouts = [];
}

componentWillUnmount() {
if (this.timeout) {
clearTimeout(this.timeout);
}
this.transitionTimeouts.forEach((timeout) => {
clearTimeout(timeout);
});
}

componentWillEnter(done) {
if (this.props.enter) {
this.transition('enter', done);
this.transition('enter', done, this.props.enterTimeout);
}
else {
done();
Expand All @@ -100,7 +111,7 @@ export class CSSTransitionGroupChild extends Component {

componentWillLeave(done) {
if (this.props.leave) {
this.transition('leave', done);
this.transition('leave', done, this.props.leaveTimeout);
}
else {
done();
Expand Down
93 changes: 93 additions & 0 deletions tests/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,38 @@ class TodoList extends Component {
}
}

class TodoListWithTimeout extends Component {
state = {
items: ['hello', 'world', 'click', 'me']
};

handleAdd(item) {
let { items } = this.state;
items = items.concat(item);
this.setState({ items });
}

handleRemove(i) {
let { items } = this.state;
items.splice(i, 1);
this.setState({ items });
}

render(_, { items }) {
return (
<div>
<CSSTransitionGroup transitionName="example" transitionEnterTimeout={500} transitionLeaveTimeout={200}>
{ items.map( (item, i) => (
<Todo key={item} onClick={this.handleRemove.bind(this, i)}>
{item}
</Todo>
)) }
</CSSTransitionGroup>
</div>
);
}
}

class SVGList extends Component {
state = {
items: ['hello', 'world', 'click', 'me']
Expand Down Expand Up @@ -182,6 +214,67 @@ describe('CSSTransitionGroup', () => {
});
});

describe('CSSTransitionGroup: timeout', () => {
let container = document.createElement('div'),
list, root;
document.body.appendChild(container);

let $ = s => [].slice.call(container.querySelectorAll(s));

beforeEach( () => {
root = render(<div><Nothing /></div>, container, root);
root = render(<div><TodoListWithTimeout ref={c => list=c} /></div>, container, root);
});

afterEach( () => {
list = null;
});

it('create works', () => {
expect($('.item')).to.have.length(4);
});

it('transitionLeave works with the transitionLeaveTimeout', done => {
// this.timeout(5999);
list.handleRemove(0);

// make sure -leave class was added
setTimeout( () => {
expect($('.item')).to.have.length(4);

expect($('.item')[0].className).to.contain('example-leave');
expect($('.item')[0].className).to.contain('example-leave-active');
}, 100);

// then make sure it's gone
setTimeout( () => {
expect($('.item')).to.have.length(3);
done();
}, 300);
});

it('transitionEnter works with the transitionEnterTimeout', done => {
// this.timeout(5999);
list.handleAdd(Date.now());

setTimeout( () => {
expect($('.item')).to.have.length(5);

expect($('.item')[4].className).to.contain('example-enter');
expect($('.item')[4].className).to.contain('example-enter-active');
}, 300);

setTimeout( () => {
expect($('.item')).to.have.length(5);

expect($('.item')[4].className).not.to.contain('example-enter');
expect($('.item')[4].className).not.to.contain('example-enter-active');

done();
}, 600);
});
});

describe('CSSTransitionGroup: SVG', () => {
let container = document.createElement('div'),
list, root;
Expand Down

0 comments on commit 810f9f2

Please sign in to comment.