UNPKG

uikit

Version:

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

160 lines (131 loc) 4.58 kB
import Margin from './margin'; import Class from '../mixin/class'; import Scroll from '../mixin/scroll'; import { addClass, children, css, hasClass, scrolledOver, sortBy, toFloat, toggleClass, } from 'uikit-util'; export default { extends: Margin, mixins: [Class, Scroll], name: 'grid', props: { masonry: Boolean, parallax: Number, }, data: { margin: 'uk-grid-margin', clsStack: 'uk-grid-stack', masonry: false, parallax: 0, }, connected() { this.masonry && addClass(this.$el, 'uk-flex-top uk-flex-wrap-top'); }, update: [ { write({ columns }) { toggleClass(this.$el, this.clsStack, columns.length < 2); }, events: ['resize'], }, { read(data) { let { columns, rows } = data; // Filter component makes elements positioned absolute if ( !columns.length || (!this.masonry && !this.parallax) || positionedAbsolute(this.$el) ) { data.translates = false; return false; } let translates = false; const nodes = children(this.$el); const columnHeights = getColumnHeights(columns); const margin = getMarginTop(nodes, this.margin) * (rows.length - 1); const elHeight = Math.max(...columnHeights) + margin; if (this.masonry) { columns = columns.map((column) => sortBy(column, 'offsetTop')); translates = getTranslates(rows, columns); } let padding = Math.abs(this.parallax); if (padding) { padding = columnHeights.reduce( (newPadding, hgt, i) => Math.max( newPadding, hgt + margin + (i % 2 ? padding : padding / 8) - elHeight ), 0 ); } return { padding, columns, translates, height: translates ? elHeight : '' }; }, write({ height, padding }) { css(this.$el, 'paddingBottom', padding || ''); height !== false && css(this.$el, 'height', height); }, events: ['resize'], }, { read() { if (this.parallax && positionedAbsolute(this.$el)) { return false; } return { scrolled: this.parallax ? scrolledOver(this.$el) * Math.abs(this.parallax) : false, }; }, write({ columns, scrolled, translates }) { if (scrolled === false && !translates) { return; } columns.forEach((column, i) => column.forEach((el, j) => css( el, 'transform', !scrolled && !translates ? '' : `translateY(${ (translates && -translates[i][j]) + (scrolled ? (i % 2 ? scrolled : scrolled / 8) : 0) }px)` ) ) ); }, events: ['scroll', 'resize'], }, ], }; function positionedAbsolute(el) { return children(el).some((el) => css(el, 'position') === 'absolute'); } function getTranslates(rows, columns) { const rowHeights = rows.map((row) => Math.max(...row.map((el) => el.offsetHeight))); return columns.map((elements) => { let prev = 0; return elements.map( (element, row) => (prev += row ? rowHeights[row - 1] - elements[row - 1].offsetHeight : 0) ); }); } function getMarginTop(nodes, cls) { const [node] = nodes.filter((el) => hasClass(el, cls)); return toFloat(node ? css(node, 'marginTop') : css(nodes[0], 'paddingLeft')); } function getColumnHeights(columns) { return columns.map((column) => column.reduce((sum, el) => sum + el.offsetHeight, 0)); }