/**
* Copyright by AIWSolutions.
*/
import React from 'react';
import PropTypes from 'prop-types';
import _ from 'lodash';
import { computeStyle, MARGIN_PROPS, PADDING_PROPS } from './utils';
import './flexbox.css';
/**
* Represent a Flex container.
* This container has built in shouldComponentUpdate to prevent unwanted updates when there is no changes on
* its property
* There is also basic property filtering for invalid propery when passing property from its parent like this:
* <Flex
* {...props}
* />
*
* @property {string} align - Shorthand for css align-items, This defines the default behaviour for how flex
* items are laid out along the cross axis on the current line.
* @property {bool} auto - Shorthand for css flex: 1 1 auto
* @property {string | number} basis - Shorthand for css flex-basis, it defines the default size of an element
* before the remaining space is distributed
* @property {string} className - By default this element will have className of 'flex' or 'inline-flex', this
* property is for extra classes
* @property {number} col - How many x of 1/12 of width of the parent container that this element should take.
* This equals to css width: (col * 100 / 12)%
* @property {bool} fullWidth - Shorthand for css width: 100%
* @property {number} grow - Shorthand for css flex-grow, it defines what amount of the available
* space inside the flex container the item should take up
* @property {bool} inline - Make this Flex to be inline-flex which displays itself as inline
* @property {string} justify - Shorthand for css justify-content, it defines the alignment along the main axis.
* @property {number} order - Controls the order in which this Box appears in the Flex container
* @property {bool} reverse - Reverse the direction of aligning items
* @property {number} shrink - Shorthand for css flex-shrink, it defines the ability for a flex item
* to shrink if necessary.
* @property {object} style - Element style
* @property {string} wrap - Shorthand for css flex-wrap, it allows the items to wrap as needed
*/
class Flex extends React.Component {
static propTypes = {
auto: PropTypes.bool,
column: PropTypes.bool,
reverse: PropTypes.bool,
order: PropTypes.number,
grow: PropTypes.number,
shrink: PropTypes.number,
wrap: PropTypes.oneOf([
'nowrap',
'wrap',
'wrap-reverse',
]),
justify: PropTypes.oneOf([
'flex-start',
'flex-end',
'center',
'space-between',
'space-around',
]),
align: PropTypes.oneOf([
'flex-start',
'flex-end',
'center',
'stretch',
'baseline',
]),
fullWidth: PropTypes.bool,
inline: PropTypes.bool,
col: PropTypes.oneOf([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),
style: PropTypes.object,
className: PropTypes.string,
};
static ownProps = [..._.keys(Flex.propTypes), ...MARGIN_PROPS, ...PADDING_PROPS];
shouldComponentUpdate(nextProps) {
return this.props.children !== nextProps.children
|| !_.isEqual(_.pick(this.props, Flex.ownProps), _.pick(nextProps, Flex.ownProps));
}
render() {
const {
children,
auto,
order,
grow,
shrink,
basis,
column,
reverse,
wrap,
justify,
align,
fullWidth,
style,
col,
inline,
className,
shouldUpdate,
...others
} = this.props;
/* eslint no-nested-ternary: 0 */
const flexDirection = column ? (reverse ? 'column-reverse' : 'column')
: (reverse ? 'row-reverse' : 'row');
const flexStyle = {
WebkitOrder: order,
order,
WebkitBoxSizing: 'border-box',
boxSizing: 'border-box',
WebkitFlexGrow: grow,
flexGrow: grow,
WebkitFlexShrink: shrink,
flexShrink: shrink,
WebkitFlexBasis: basis,
flexBasis: basis,
WebkitFlexDirection: flexDirection,
flexDirection,
WebkitFlexWrap: wrap,
flexWrap: wrap,
WebkitJustifyContent: justify,
justifyContent: justify,
WebkitAlignItems: align,
alignItems: align,
};
if (auto) {
flexStyle.WebkitFlex = '1 1 auto';
flexStyle.flex = '1 1 auto';
}
if (fullWidth) {
flexStyle.width = '100%';
}
if (col) {
const widthPercentage = col * 100 / 12;
flexStyle.width = `${widthPercentage.toFixed(2)}%`;
}
const computedStyle = computeStyle(others);
const classString = inline ? 'inline-flex' : 'flex';
return (
<div
className={classString + (className ? ` ${className}` : '')}
style={Object.assign({}, flexStyle, computedStyle.style, style)}
{...computedStyle.others}
>
{children}
</div>
);
}
}
export default Flex;