uikit
Version:
UIkit is a lightweight and modular front-end framework for developing fast and powerful web interfaces.
136 lines (109 loc) • 3.13 kB
JavaScript
import Resize from '../mixin/resize';
import {
isRtl,
isVisible,
observeMutation,
offsetPosition,
toArray,
toggleClass,
} from 'uikit-util';
export default {
mixins: [Resize],
props: {
margin: String,
firstColumn: Boolean,
},
data: {
margin: 'uk-margin-small-top',
firstColumn: 'uk-first-column',
},
resizeTargets() {
return [this.$el, ...toArray(this.$el.children)];
},
connected() {
this.registerObserver(
observeMutation(this.$el, () => this.$reset(), {
childList: true,
})
);
},
update: {
read() {
const rows = getRows(this.$el.children);
return {
rows,
columns: getColumns(rows),
};
},
write({ columns, rows }) {
for (const row of rows) {
for (const column of row) {
toggleClass(column, this.margin, rows[0] !== row);
toggleClass(column, this.firstColumn, columns[0].includes(column));
}
}
},
events: ['resize'],
},
};
export function getRows(items) {
return sortBy(items, 'top', 'bottom');
}
function getColumns(rows) {
const columns = [];
for (const row of rows) {
const sorted = sortBy(row, 'left', 'right');
for (let j = 0; j < sorted.length; j++) {
columns[j] = columns[j] ? columns[j].concat(sorted[j]) : sorted[j];
}
}
return isRtl ? columns.reverse() : columns;
}
function sortBy(items, startProp, endProp) {
const sorted = [[]];
for (const el of items) {
if (!isVisible(el)) {
continue;
}
let dim = getOffset(el);
for (let i = sorted.length - 1; i >= 0; i--) {
const current = sorted[i];
if (!current[0]) {
current.push(el);
break;
}
let startDim;
if (current[0].offsetParent === el.offsetParent) {
startDim = getOffset(current[0]);
} else {
dim = getOffset(el, true);
startDim = getOffset(current[0], true);
}
if (dim[startProp] >= startDim[endProp] - 1 && dim[startProp] !== startDim[startProp]) {
sorted.push([el]);
break;
}
if (dim[endProp] - 1 > startDim[startProp] || dim[startProp] === startDim[startProp]) {
current.push(el);
break;
}
if (i === 0) {
sorted.unshift([el]);
break;
}
}
}
return sorted;
}
function getOffset(element, offset = false) {
let { offsetTop, offsetLeft, offsetHeight, offsetWidth } = element;
if (offset) {
[offsetTop, offsetLeft] = offsetPosition(element);
}
return {
top: offsetTop,
left: offsetLeft,
bottom: offsetTop + offsetHeight,
right: offsetLeft + offsetWidth,
};
}