UNPKG

uikit

Version:

UIkit is a lightweight and modular front-end framework for developing fast and powerful web interfaces.

117 lines (97 loc) 2.96 kB
import { children, isRtl, isVisible, offsetPosition, toggleClass } from 'uikit-util'; import { mutation, resize } from '../api/observables'; export default { props: { margin: String, firstColumn: Boolean, }, data: { margin: 'uk-margin-small-top', firstColumn: 'uk-first-column', }, observe: [ mutation({ options: { childList: true, }, }), mutation({ options: { attributes: true, attributeFilter: ['style'], }, target: ({ $el }) => [$el, ...children($el)], }), resize({ target: ({ $el }) => [$el, ...children($el)], }), ], update: { read() { return { rows: getRows(children(this.$el)), }; }, write({ rows }) { for (const row of rows) { for (const el of row) { toggleClass(el, this.margin, rows[0] !== row); toggleClass(el, this.firstColumn, row[isRtl ? row.length - 1 : 0] === el); } } }, events: ['resize'], }, }; export function getRows(elements) { const sorted = [[]]; const withOffset = elements.some( (el, i) => i && elements[i - 1].offsetParent !== el.offsetParent, ); for (const el of elements) { if (!isVisible(el)) { continue; } const offset = getOffset(el, withOffset); for (let i = sorted.length - 1; i >= 0; i--) { const current = sorted[i]; if (!current[0]) { current.push(el); break; } const offsetCurrent = getOffset(current[0], withOffset); if (offset.top >= offsetCurrent.bottom - 1 && offset.top !== offsetCurrent.top) { sorted.push([el]); break; } if (offset.bottom - 1 > offsetCurrent.top || offset.top === offsetCurrent.top) { let j = current.length - 1; for (; j >= 0; j--) { const offsetCurrent = getOffset(current[j], withOffset); if (offset.left >= offsetCurrent.left) { break; } } current.splice(j + 1, 0, 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, }; }