185 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
			
		
		
	
	
			185 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
| // https://github.com/yiminghe/css-animation 1.5.0
 | |
| 
 | |
| import Event from './Event';
 | |
| import classes from '../component-classes';
 | |
| import { requestAnimationTimeout, cancelAnimationTimeout } from '../requestAnimationTimeout';
 | |
| 
 | |
| const isCssAnimationSupported = Event.endEvents.length !== 0;
 | |
| const capitalPrefixes = [
 | |
|   'Webkit',
 | |
|   'Moz',
 | |
|   'O',
 | |
|   // ms is special .... !
 | |
|   'ms',
 | |
| ];
 | |
| const prefixes = ['-webkit-', '-moz-', '-o-', 'ms-', ''];
 | |
| 
 | |
| function getStyleProperty(node, name) {
 | |
|   // old ff need null, https://developer.mozilla.org/en-US/docs/Web/API/Window/getComputedStyle
 | |
|   const style = window.getComputedStyle(node, null);
 | |
|   let ret = '';
 | |
|   for (let i = 0; i < prefixes.length; i++) {
 | |
|     ret = style.getPropertyValue(prefixes[i] + name);
 | |
|     if (ret) {
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| function fixBrowserByTimeout(node) {
 | |
|   if (isCssAnimationSupported) {
 | |
|     const transitionDelay = parseFloat(getStyleProperty(node, 'transition-delay')) || 0;
 | |
|     const transitionDuration = parseFloat(getStyleProperty(node, 'transition-duration')) || 0;
 | |
|     const animationDelay = parseFloat(getStyleProperty(node, 'animation-delay')) || 0;
 | |
|     const animationDuration = parseFloat(getStyleProperty(node, 'animation-duration')) || 0;
 | |
|     const time = Math.max(transitionDuration + transitionDelay, animationDuration + animationDelay);
 | |
|     // sometimes, browser bug
 | |
|     node.rcEndAnimTimeout = setTimeout(() => {
 | |
|       node.rcEndAnimTimeout = null;
 | |
|       if (node.rcEndListener) {
 | |
|         node.rcEndListener();
 | |
|       }
 | |
|     }, time * 1000 + 200);
 | |
|   }
 | |
| }
 | |
| 
 | |
| function clearBrowserBugTimeout(node) {
 | |
|   if (node.rcEndAnimTimeout) {
 | |
|     clearTimeout(node.rcEndAnimTimeout);
 | |
|     node.rcEndAnimTimeout = null;
 | |
|   }
 | |
| }
 | |
| 
 | |
| const cssAnimation = (node, transitionName, endCallback) => {
 | |
|   const nameIsObj = typeof transitionName === 'object';
 | |
|   const className = nameIsObj ? transitionName.name : transitionName;
 | |
|   const activeClassName = nameIsObj ? transitionName.active : `${transitionName}-active`;
 | |
|   let end = endCallback;
 | |
|   let start;
 | |
|   let active;
 | |
|   const nodeClasses = classes(node);
 | |
| 
 | |
|   if (endCallback && Object.prototype.toString.call(endCallback) === '[object Object]') {
 | |
|     end = endCallback.end;
 | |
|     start = endCallback.start;
 | |
|     active = endCallback.active;
 | |
|   }
 | |
| 
 | |
|   if (node.rcEndListener) {
 | |
|     node.rcEndListener();
 | |
|   }
 | |
| 
 | |
|   node.rcEndListener = e => {
 | |
|     if (e && e.target !== node) {
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     if (node.rcAnimTimeout) {
 | |
|       cancelAnimationTimeout(node.rcAnimTimeout);
 | |
|       node.rcAnimTimeout = null;
 | |
|     }
 | |
| 
 | |
|     clearBrowserBugTimeout(node);
 | |
| 
 | |
|     nodeClasses.remove(className);
 | |
|     nodeClasses.remove(activeClassName);
 | |
| 
 | |
|     Event.removeEndEventListener(node, node.rcEndListener);
 | |
|     node.rcEndListener = null;
 | |
| 
 | |
|     // Usually this optional end is used for informing an owner of
 | |
|     // a leave animation and telling it to remove the child.
 | |
|     if (end) {
 | |
|       end();
 | |
|     }
 | |
|   };
 | |
| 
 | |
|   Event.addEndEventListener(node, node.rcEndListener);
 | |
| 
 | |
|   if (start) {
 | |
|     start();
 | |
|   }
 | |
|   nodeClasses.add(className);
 | |
| 
 | |
|   node.rcAnimTimeout = requestAnimationTimeout(() => {
 | |
|     node.rcAnimTimeout = null;
 | |
| 
 | |
|     nodeClasses.add(className);
 | |
|     nodeClasses.add(activeClassName);
 | |
| 
 | |
|     if (active) {
 | |
|       requestAnimationTimeout(active, 0);
 | |
|     }
 | |
|     fixBrowserByTimeout(node);
 | |
|     // 30ms for firefox
 | |
|   }, 30);
 | |
| 
 | |
|   return {
 | |
|     stop() {
 | |
|       if (node.rcEndListener) {
 | |
|         node.rcEndListener();
 | |
|       }
 | |
|     },
 | |
|   };
 | |
| };
 | |
| 
 | |
| cssAnimation.style = (node, style, callback) => {
 | |
|   if (node.rcEndListener) {
 | |
|     node.rcEndListener();
 | |
|   }
 | |
| 
 | |
|   node.rcEndListener = e => {
 | |
|     if (e && e.target !== node) {
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     if (node.rcAnimTimeout) {
 | |
|       cancelAnimationTimeout(node.rcAnimTimeout);
 | |
|       node.rcAnimTimeout = null;
 | |
|     }
 | |
| 
 | |
|     clearBrowserBugTimeout(node);
 | |
| 
 | |
|     Event.removeEndEventListener(node, node.rcEndListener);
 | |
|     node.rcEndListener = null;
 | |
| 
 | |
|     // Usually this optional callback is used for informing an owner of
 | |
|     // a leave animation and telling it to remove the child.
 | |
|     if (callback) {
 | |
|       callback();
 | |
|     }
 | |
|   };
 | |
| 
 | |
|   Event.addEndEventListener(node, node.rcEndListener);
 | |
| 
 | |
|   node.rcAnimTimeout = requestAnimationTimeout(() => {
 | |
|     for (const s in style) {
 | |
|       if (style.hasOwnProperty(s)) {
 | |
|         node.style[s] = style[s];
 | |
|       }
 | |
|     }
 | |
|     node.rcAnimTimeout = null;
 | |
|     fixBrowserByTimeout(node);
 | |
|   }, 0);
 | |
| };
 | |
| 
 | |
| cssAnimation.setTransition = (node, p, value) => {
 | |
|   let property = p;
 | |
|   let v = value;
 | |
|   if (value === undefined) {
 | |
|     v = property;
 | |
|     property = '';
 | |
|   }
 | |
|   property = property || '';
 | |
|   capitalPrefixes.forEach(prefix => {
 | |
|     node.style[`${prefix}Transition${property}`] = v;
 | |
|   });
 | |
| };
 | |
| 
 | |
| cssAnimation.isCssAnimationSupported = isCssAnimationSupported;
 | |
| 
 | |
| export { isCssAnimationSupported };
 | |
| 
 | |
| export default cssAnimation;
 |