UNPKG

preact-css-transition-group

Version:

Apply CSS transitions when adding or removing Preact components/elements.

125 lines (103 loc) 3.02 kB
/** * Copyright 2013-2014, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * * Additional credit to the Author of rc-css-transition-group: https://github.com/yiminghe * File originally extracted from the React source, converted to ES6 by https://github.com/developit */ import { h, Component } from 'preact'; import { getComponentBase, onlyChild } from './util'; import { addClass, removeClass } from './CSSCore'; import { addEndEventListener, removeEndEventListener } from './TransitionEvents'; const TICK = 17; export class CSSTransitionGroupChild extends Component { 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(); } this.endListener = (e) => { if (e && e.target!==node) return; clearTimeout(timer); removeClass(node, className); removeClass(node, activeClassName); removeEndEventListener(node, this.endListener); this.endListener = null; // Usually this optional callback is used for informing an owner of // a leave animation and telling it to remove the child. if (finishCallback) { finishCallback(); } }; if (timeout) { timer = setTimeout(this.endListener, timeout); this.transitionTimeouts.push(timer); } else { addEndEventListener(node, this.endListener); } addClass(node, className); // Need to do this to actually trigger a transition. this.queueClass(activeClassName); } queueClass(className) { this.classNameQueue.push(className); if (!this.timeout) { this.timeout = setTimeout(this.flushClassNameQueue, TICK); } } stop() { if (this.timeout) { clearTimeout(this.timeout); this.classNameQueue.length = 0; this.timeout = null; } if (this.endListener) { this.endListener(); } } flushClassNameQueue = () => { if (getComponentBase(this)) { addClass(getComponentBase(this), this.classNameQueue.join(' ')); } this.classNameQueue.length = 0; this.timeout = null; }; 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.props.enterTimeout); } else { done(); } } componentWillLeave(done) { if (this.props.leave) { this.transition('leave', done, this.props.leaveTimeout); } else { done(); } } render() { return onlyChild(this.props.children); } }