vuikit
Version:
A Vuejs component library based on UIkit
170 lines (136 loc) • 3.42 kB
JavaScript
/**
* Vuikit 0.7.0
* (c) 2018 Miljan Aleksic
* @license MIT
*/
import {
get,
includes,
debounce,
isObject,
isString,
toInteger,
isUndefined
} from 'vuikit/core/util'
import {
positionAt,
flipPosition,
getPositionAxis
} from 'vuikit/core/helpers/dom/position'
import css from 'vuikit/core/helpers/css'
import { warn } from 'vuikit/core/helpers/debug'
import { addClass } from 'vuikit/core/helpers/dom/class'
import { on, off, offAll } from 'vuikit/core/helpers/dom/event'
let uid = 'v-position'
const positions = [
'top-left',
'top-center',
'top-right',
'bottom-left',
'bottom-center',
'bottom-right',
'left-top',
'left-center',
'left-bottom',
'right-top',
'right-center',
'right-bottom'
]
export default {
inserted (el, binding, vnode) {
const ctx = getContext(el, binding, vnode)
if (ctx) {
position(ctx)
}
},
componentUpdated (el, binding, vnode) {
const ctx = getContext(el, binding, vnode)
if (ctx) {
position(ctx)
}
},
unbind (el, binding, vnode) {
offAll(uid)
}
}
function position (ctx) {
const { el, props, vnode } = ctx
const { target, position, offset, boundary, flip, classPrefix } = props
if (!includes(positions, position)) {
warn('Invalid v-position position', vnode)
}
let [dir, align] = position.split('-')
// remove any position class
const classesRx = new RegExp(`${classPrefix}-(top|bottom|left|right)(-[a-z]+)?`)
el.className = el.className.replace(classesRx, '')
// reset pos
css(el, { top: '', left: '' })
const axis = getPositionAxis(position)
const elAttach = axis === 'x'
? `${flipPosition(dir)} ${align}`
: `${align} ${flipPosition(dir)}`
const targetAttach = axis === 'x'
? `${dir} ${align}`
: `${align} ${dir}`
const elOffset = axis === 'x'
? `${dir === 'left' ? -1 * offset : offset}`
: ` ${dir === 'top' ? -1 * offset : offset}`
const { x, y } = positionAt({
flip,
target,
boundary,
elAttach,
elOffset,
element: el,
targetAttach,
targetOffset: null
}).target
dir = axis === 'x' ? x : y
align = axis === 'x' ? y : x
// add on resize events
setResizeEvent(ctx)
// add position class
if (classPrefix) {
addClass(el, `${classPrefix}-${dir}-${align}`)
}
}
/**
* Get the directive props
**/
function getProps (ctx) {
const { vnode } = ctx
const { value } = ctx.binding
if (isUndefined(value) || !isObject(value)) {
warn('v-position configuration is missing or is not an Object', vnode.context)
return false
}
let target = value.target || null
const delay = get(value, 'delay', 0)
const flip = get(value, 'flip', true)
const classPrefix = get(value, 'classPrefix', 'v-position')
const boundary = value.boundary || window
const offset = toInteger(value.offset) || 0
const position = value.position || 'top-center'
if (isString(target)) {
target = vnode.context.$refs[target]
}
return { target, delay, offset, flip, position, boundary, classPrefix }
}
function setResizeEvent (ctx) {
off(window, 'resize', uid)
on(window, 'resize', debounce(() => {
position(ctx)
}, 50), uid)
}
/**
* Get the context used across
**/
function getContext (el, binding, vnode) {
const ctx = { el, binding, vnode }
ctx.props = getProps(ctx)
if (!ctx.props) {
binding.def.unbind(el, binding)
return
}
return ctx
}