ant-design-vue/components/_util/css-animation/index.js

180 lines
4.5 KiB
JavaScript

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(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