vuikit
Version:
A responsive Vue UI library for web site interfaces based on UIkit
278 lines (273 loc) • 8.61 kB
JavaScript
/**
* Vuikit 0.8.10
* (c) 2018 Miljan Aleksic
* @license MIT
**/
/* Substantial part of the code is adapted from UIkit,
Copyright (c) 2013-2018 YOOtheme GmbH, getuikit.com */
import { css } from './style';
import { isVisible } from './filter';
import { clamp, each, endsWith, includes, intersectRect, isDocument, isUndefined, isWindow, toFloat, toNode, ucfirst } from './lang';
var dirs = {
width: ['x', 'left', 'right'],
height: ['y', 'top', 'bottom']
};
function positionAt (element, target, elAttach, targetAttach, elOffset, targetOffset, flip, boundary) {
elAttach = getPos(elAttach);
targetAttach = getPos(targetAttach);
var flipped = {element: elAttach, target: targetAttach};
if (!element || !target) {
return flipped
}
var dim = getDimensions(element);
var targetDim = getDimensions(target);
var position = targetDim;
moveTo(position, elAttach, dim, -1);
moveTo(position, targetAttach, targetDim, 1);
elOffset = getOffsets(elOffset, dim.width, dim.height);
targetOffset = getOffsets(targetOffset, targetDim.width, targetDim.height);
elOffset['x'] += targetOffset['x'];
elOffset['y'] += targetOffset['y'];
position.left += elOffset['x'];
position.top += elOffset['y'];
boundary = getDimensions(boundary || window(element));
if (flip) {
each(dirs, function (ref, prop) {
var dir = ref[0];
var align = ref[1];
var alignFlip = ref[2];
if (!(flip === true || includes(flip, dir))) {
return
}
var elemOffset = elAttach[dir] === align
? -dim[prop]
: elAttach[dir] === alignFlip
? dim[prop]
: 0;
var targetOffset = targetAttach[dir] === align
? targetDim[prop]
: targetAttach[dir] === alignFlip
? -targetDim[prop]
: 0;
if (position[align] < boundary[align] || position[align] + dim[prop] > boundary[alignFlip]) {
var centerOffset = dim[prop] / 2;
var centerTargetOffset = targetAttach[dir] === 'center' ? -targetDim[prop] / 2 : 0;
elAttach[dir] === 'center' && (
apply(centerOffset, centerTargetOffset) ||
apply(-centerOffset, -centerTargetOffset)
) || apply(elemOffset, targetOffset);
}
function apply (elemOffset, targetOffset) {
var newVal = position[align] + elemOffset + targetOffset - elOffset[dir] * 2;
if (newVal >= boundary[align] && newVal + dim[prop] <= boundary[alignFlip]) {
position[align] = newVal;
['element', 'target'].forEach(function (el) {
flipped[el][dir] = !elemOffset
? flipped[el][dir]
: flipped[el][dir] === dirs[prop][1]
? dirs[prop][2]
: dirs[prop][1];
});
return true
}
}
});
}
offset(element, position);
return flipped
}
function offset (element, coordinates) {
element = toNode(element);
if (coordinates) {
var currentOffset = offset(element);
var pos = css(element, 'position');
['left', 'top'].forEach(function (prop) {
if (prop in coordinates) {
var value = css(element, prop);
element.style[prop] = ((coordinates[prop] - currentOffset[prop]) +
toFloat(pos === 'absolute' && value === 'auto' ? position(element)[prop] : value)) + "px";
}
});
return
}
return getDimensions(element)
}
function getDimensions (element) {
element = toNode(element);
var ref = window(element);
var top = ref.pageYOffset;
var left = ref.pageXOffset;
if (isWindow(element)) {
var height = element.innerHeight;
var width = element.innerWidth;
return {
top: top,
left: left,
height: height,
width: width,
bottom: top + height,
right: left + width
}
}
var display = false;
if (!isVisible(element)) {
display = element.style.display;
element.style.display = 'block';
}
var rect = element.getBoundingClientRect();
if (display !== false) {
element.style.display = display;
}
return {
height: rect.height,
width: rect.width,
top: rect.top + top,
left: rect.left + left,
bottom: rect.bottom + top,
right: rect.right + left
}
}
function position (element) {
element = toNode(element);
var parent = offsetParent(element);
var parentOffset = parent === docEl(element) ? {top: 0, left: 0} : offset(parent);
var ref = ['top', 'left'].reduce(function (props, prop) {
var propName = ucfirst(prop);
props[prop] -= parentOffset[prop] +
(toFloat(css(element, ("margin" + propName))) || 0) +
(toFloat(css(parent, ("border" + propName + "Width"))) || 0);
return props
}, offset(element));
var top = ref.top;
var left = ref.left;
return {top: top, left: left}
}
function offsetParent (element) {
var parent = toNode(element).offsetParent;
while (parent && css(parent, 'position') === 'static') {
parent = parent.offsetParent;
}
return parent || docEl(element)
}
var height = dimension('height');
var width = dimension('width');
function dimension (prop) {
var propName = ucfirst(prop);
return function (element, value) {
element = toNode(element);
if (isUndefined(value)) {
if (isWindow(element)) {
return element[("inner" + propName)]
}
if (isDocument(element)) {
var doc = element.documentElement;
return Math.max(doc[("offset" + propName)], doc[("scroll" + propName)])
}
value = css(element, prop);
value = value === 'auto' ? element[("offset" + propName)] : toFloat(value) || 0;
return getContentSize(prop, element, value)
} else {
css(element, prop, !value && value !== 0
? ''
: getContentSize(prop, element, value) + 'px'
);
}
}
}
function getContentSize (prop, element, value) {
return css(element, 'boxSizing') === 'border-box' ? dirs[prop].slice(1).map(ucfirst).reduce(function (value, prop) { return value -
toFloat(css(element, ("padding" + prop))) -
toFloat(css(element, ("border" + prop + "Width"))); }
, value) : value
}
function moveTo (position, attach, dim, factor) {
each(dirs, function (ref, prop) {
var dir = ref[0];
var align = ref[1];
var alignFlip = ref[2];
if (attach[dir] === alignFlip) {
position[align] += dim[prop] * factor;
} else if (attach[dir] === 'center') {
position[align] += dim[prop] * factor / 2;
}
});
}
function getPos (pos) {
var x = /left|center|right/;
var y = /top|center|bottom/;
pos = (pos || '').split(' ');
if (pos.length === 1) {
pos = x.test(pos[0])
? pos.concat(['center'])
: y.test(pos[0])
? ['center'].concat(pos)
: ['center', 'center'];
}
return {
x: x.test(pos[0]) ? pos[0] : 'center',
y: y.test(pos[1]) ? pos[1] : 'center'
}
}
function getOffsets (offsets, width, height) {
var ref = (offsets || '').split(' ');
var x = ref[0];
var y = ref[1];
return {
x: x ? toFloat(x) * (endsWith(x, '%') ? width / 100 : 1) : 0,
y: y ? toFloat(y) * (endsWith(y, '%') ? height / 100 : 1) : 0
}
}
function flipPosition (pos) {
switch (pos) {
case 'left':
return 'right'
case 'right':
return 'left'
case 'top':
return 'bottom'
case 'bottom':
return 'top'
default:
return pos
}
}
function isInView (element, top, left) {
if ( top === void 0 ) top = 0;
if ( left === void 0 ) left = 0;
element = toNode(element);
var win = window(element);
return intersectRect(element.getBoundingClientRect(), {
top: top,
left: left,
bottom: top + height(win),
right: left + width(win)
})
}
function scrolledOver (element) {
element = toNode(element);
var win = window(element);
var doc = document(element);
var elHeight = element.offsetHeight;
var top = positionTop(element);
var vp = height(win);
var vh = vp + Math.min(0, top - vp);
var diff = Math.max(0, vp - (height(doc) - (top + elHeight)));
return clamp(((vh + win.pageYOffset - top) / ((vh + (elHeight - (diff < vp ? diff : 0))) / 100)) / 100)
}
function positionTop (element) {
var top = 0;
do {
top += element.offsetTop;
} while ((element = element.offsetParent))
return top
}
function window (element) {
return isWindow(element) ? element : document(element).defaultView
}
function document (element) {
return toNode(element).ownerDocument
}
function docEl (element) {
return document(element).documentElement
}
export { positionAt, offset, position, height, width, flipPosition, isInView, scrolledOver };