react-flexbox-layout
Version:
Simple flexible layouts for IE9+
196 lines (158 loc) • 4.97 kB
JSX
import each from "lodash/each";
import isNumber from "lodash/isNumber";
import React from "react";
function isEmptyNode (node) {
return node == null || node.type === "noscript";
}
export function mapNonEmpty(children, fn) {
let offset = 0;
return React.Children.map(children, function(child, index) {
if (isEmptyNode(child)) {
offset += 1;
return child;
}
return fn(child, index - offset);
});
}
export function forEachNonEmpty(children, fn) {
let offset = 0;
React.Children.forEach(children, function(child, index) {
if (isEmptyNode(child)) {
offset += 1;
return;
}
fn(child, index - offset);
});
}
export function countNonEmpty(children) {
let count = 0;
React.Children.forEach(children, function(child) {
if (!isEmptyNode(child)) {
count += 1;
}
});
return count;
}
export function getVGutterSizes(children, defaultGutter) {
return getGutterSizes('gutterTop', 'gutterBottom', children, defaultGutter);
}
export function getHGutterSizes(children, defaultGutter) {
return getGutterSizes('gutterLeft', 'gutterRight', children, defaultGutter);
}
function getGutterSizes(gutterPrevKey, gutterNextKey, children, defaultGutter) {
let childrenCount = countNonEmpty(children);
let gutterSizes = new Array(childrenCount);
// fill in gutters specified on children
forEachNonEmpty(children, (child, index) => {
let gutterPrev = child.props && child.props[gutterPrevKey],
gutterNext = child.props && child.props[gutterNextKey];
if (index === 0) {
gutterSizes[0] = gutterPrev;
} else {
if (isNumber(gutterSizes[index])) {
if (isNumber(gutterPrev)) {
gutterSizes[index] = Math.max(gutterSizes[index], gutterPrev);
}
} else {
gutterSizes[index] = gutterPrev;
}
}
gutterSizes[index + 1] = gutterNext;
});
// fill in blank gutters with the default
gutterSizes = gutterSizes.map((gutter, index) => {
return isNumber(gutter) ? gutter :
index === 0 || index === childrenCount ? 0 :
defaultGutter;
});
return gutterSizes;
}
const sizeRegex = /^\s*(\d+)([^\s]+)\s*$/;
export function sumSizes(dimension, items) {
const sum = {};
items.forEach((item) => {
const size = item.props[dimension] || (item.props.style && item.props.style[dimension]);
if (size === undefined || size === null) { return; }
if (isNumber(size)) {
addTo(sum, 'px', size);
} else {
let matches = sizeRegex.exec(size);
if (matches) {
let [, value, unit] = matches;
addTo(sum, unit, parseFloat(value));
}
}
});
return sum;
}
export function addTo(map, key, value) {
if (!map[key]) {
map[key] = value;
} else {
map[key] += value;
}
}
export function getSizeCalc(usedSpace, flexGrow, totalFlexGrow) {
const ratio = flexGrow / totalFlexGrow;
const expressions = [`${100 * ratio}%`];
each(usedSpace, (value, unit) => {
expressions.push(`${value * ratio}${unit}`);
});
return `calc(${expressions.join(' - ')})`;
}
export function normalizeAlign(align) {
let normalized;
switch (align) {
case "top":
normalized = 'flex-start';
break;
case "middle":
normalized = 'center';
break;
case 'bottom':
normalized = 'flex-end';
break;
default:
normalized = align;
break;
}
return normalized;
}
export function normalizeJustify(justify) {
switch (justify) {
case "left":
return 'flex-start';
case "center":
return 'center';
case 'right':
return 'flex-end';
}
}
export function makeVLayoutItemChildProps(parentProps, childProps = {}, index, gutterSizes, gutterMultiplier) {
var props = {};
if (index === 0) {
props._gutterTop = gutterSizes[0] ? gutterSizes[0] * gutterMultiplier + parentProps.gutterUnit : undefined;
}
props._gutterBottom = gutterSizes[index + 1] ? gutterSizes[index + 1] * gutterMultiplier + parentProps.gutterUnit : undefined;
props.justify = childProps.justify || parentProps.justifyItems;
return props;
}
export function makeHLayoutItemChildProps(parentProps, childProps = {}, index, gutterSizes, gutterMultiplier) {
var props = {};
if (index === 0) {
props._gutterLeft = gutterSizes[0] ? gutterSizes[0] * gutterMultiplier + parentProps.gutterUnit : undefined;
}
props._gutterRight = gutterSizes[index + 1] ? gutterSizes[index + 1] * gutterMultiplier + parentProps.gutterUnit : undefined;
props.align = childProps.align || parentProps.alignItems;
return props;
}
export function didDefineWidth(props) {
return props.width != null || (props.style && props.style.width) != null;
}
export function didDefineHeight(props) {
return props.height != null || (props.style && props.style.height) != null;
}
export function pxToUnit(dimensionString) {
if (!dimensionString) { return 0; }
return parseInt(dimensionString.slice(0, -2), 10);
}