vuikit
Version:
A responsive Vue UI library for web site interfaces based on UIkit
160 lines (118 loc) • 3.88 kB
JavaScript
/**
* Copyright (c) 2013-2018 YOOtheme GmbH, getuikit.com
*/
/* eslint-disable prefer-promise-reject-errors */
import {attr} from './attr'
import {Promise} from './promise'
import {once, trigger} from './event'
import {css, propName} from './style'
import {assign, startsWith, toNodes} from './lang'
import {addClass, hasClass, removeClass, removeClasses} from './class'
export function transition (element, props, duration = 400, timing = 'linear') {
return Promise.all(toNodes(element).map(element =>
new Promise((resolve, reject) => {
for (const name in props) {
const value = css(element, name)
if (value === '') {
css(element, name, value)
}
}
const timer = setTimeout(() => trigger(element, 'transitionend'), duration)
once(element, 'transitionend transitioncanceled', ({type}) => {
clearTimeout(timer)
removeClass(element, 'uk-transition')
css(element, {
'transition-property': '',
'transition-duration': '',
'transition-timing-function': ''
})
type === 'transitioncanceled' ? reject() : resolve()
}, false, ({target}) => element === target)
addClass(element, 'uk-transition')
css(element, assign({
'transition-property': Object.keys(props).map(propName).join(','),
'transition-duration': `${duration}ms`,
'transition-timing-function': timing
}, props))
})
))
}
export const Transition = {
start: transition,
stop (element) {
trigger(element, 'transitionend')
return Promise.resolve()
},
cancel (element) {
trigger(element, 'transitioncanceled')
},
inProgress (element) {
return hasClass(element, 'uk-transition')
}
}
const animationPrefix = 'uk-animation-'
const clsCancelAnimation = 'uk-cancel-animation'
export function animate (element, animation, duration = 200, origin, out) {
return Promise.all(toNodes(element).map(element =>
new Promise((resolve, reject) => {
if (hasClass(element, clsCancelAnimation)) {
requestAnimationFrame(() =>
Promise.resolve().then(() =>
animate(...arguments).then(resolve, reject)
)
)
return
}
let cls = `${animation} ${animationPrefix}${out ? 'leave' : 'enter'}`
if (startsWith(animation, animationPrefix)) {
if (origin) {
cls += ` uk-transform-origin-${origin}`
}
if (out) {
cls += ` ${animationPrefix}reverse`
}
}
reset()
once(element, 'animationend animationcancel', ({type}) => {
let hasReset = false
if (type === 'animationcancel') {
reject()
reset()
} else {
resolve()
Promise.resolve().then(() => {
hasReset = true
reset()
})
}
requestAnimationFrame(() => {
if (!hasReset) {
addClass(element, clsCancelAnimation)
requestAnimationFrame(() => removeClass(element, clsCancelAnimation))
}
})
}, false, ({target}) => element === target)
css(element, 'animationDuration', `${duration}ms`)
addClass(element, cls)
function reset () {
css(element, 'animationDuration', '')
removeClasses(element, `${animationPrefix}\\S*`)
}
})
))
}
const inProgress = new RegExp(`${animationPrefix}(enter|leave)`)
export const Animation = {
in (element, animation, duration, origin) {
return animate(element, animation, duration, origin, false)
},
out (element, animation, duration, origin) {
return animate(element, animation, duration, origin, true)
},
inProgress (element) {
return inProgress.test(attr(element, 'class'))
},
cancel (element) {
trigger(element, 'animationcancel')
}
}