UNPKG

wix-style-react

Version:
207 lines • 10.7 kB
import React, { forwardRef, useMemo } from 'react'; import PropTypes from 'prop-types'; import { st, classes, vars } from './Box.st.css'; import { stVars as spacingStVars } from '../Foundation/stylable/spacing.st.css'; import { stVars as colorsStVars } from '../Foundation/stylable/colors.st.css'; import { filterObject } from '../utils/filterObject'; import { directions, horizontalAlignmentValues, spacingValues, verticalAlignmentValues, } from './constants'; /** In case the value is a number, it's multiplied by the defined spacing unit. * Otherwise - there are three options: * 1. A Spacing Token - SP1, SP2, etc. - where the number is multiplied by the spacing unit. * 2. A predefined spacing value with semantic name (tiny, small, etc.) * 3. Space-separated values that are represented by a string (for example: "3px 3px") * */ export const formatSingleSpacingValue = value => { if (value !== undefined) { return formatSpacingValue(value); } }; export const formatComplexSpacingValue = value => { if (value !== undefined) { return value .toString() .split(' ') .map(size => formatSpacingValue(size)) .join(' '); } }; const formatSpacingValue = value => { if (isFinite(value)) { return `${value * parseInt(spacingStVars.Spacing)}px`; } return spacingStVars[value] || spacingValues[value] || `${value}`; }; const formatSizeValue = value => { if (typeof value !== 'undefined') return isFinite(value) ? `${value}px` : `${value}`; }; const Box = forwardRef(({ dataHook, gap, children, className, style, inline = false, direction = 'horizontal', align, verticalAlign, padding, paddingTop, paddingRight, paddingBottom, paddingLeft, margin, marginTop, marginRight, marginBottom, marginLeft, minWidth, maxWidth, width, minHeight, maxHeight, height, color, backgroundColor, border, borderColor, borderTopColor, borderRightColor, borderBottomColor, borderLeftColor, // Excluded props (which are handled above and should not be spread into `style`) 'data-hook': dataHookByKebabCase, flexDirection, justifyContent, alignItems, ...nativeStyles }, ref) => { const complexSpacingValues = useMemo(() => Object.entries({ padding, margin }).reduce((accu, [key, value]) => ({ ...accu, [key]: formatComplexSpacingValue(value), }), {}), [padding, margin]); const singleSpacingValues = useMemo(() => Object.entries({ paddingTop, paddingRight, paddingBottom, paddingLeft, marginTop, marginRight, marginBottom, marginLeft, }).reduce((accu, [key, value]) => ({ ...accu, [key]: formatSingleSpacingValue(value), }), {}), [ paddingTop, paddingRight, paddingBottom, paddingLeft, marginTop, marginRight, marginBottom, marginLeft, ]); const sizeValues = useMemo(() => Object.entries({ minWidth, maxWidth, width, minHeight, maxHeight, height, }).reduce((accu, [key, value]) => ({ ...accu, [key]: formatSizeValue(value), }), {}), [minWidth, maxWidth, width, minHeight, maxHeight, height]); const rootClassNames = st(classes.root, { inline, direction, alignItems: align, justifyContent: verticalAlign, }, className); const rootStyles = { ...style, // Spacing ...singleSpacingValues, ...complexSpacingValues, // Sizing ...sizeValues, // Styling color: colorsStVars[color] || color, backgroundColor: colorsStVars[backgroundColor] || backgroundColor, border, // Must be assigned before the border color props (otherwise it would override them) // Props which are spread just in case these are actually defined ...(borderColor && { borderColor: colorsStVars[borderColor] || borderColor, }), ...(borderTopColor && { borderTopColor: colorsStVars[borderTopColor] || borderTopColor, }), ...(borderRightColor && { borderRightColor: colorsStVars[borderRightColor] || borderRightColor, }), ...(borderBottomColor && { borderBottomColor: colorsStVars[borderBottomColor] || borderBottomColor, }), ...(borderLeftColor && { borderLeftColor: colorsStVars[borderLeftColor] || borderLeftColor, }), // All other props which are passed (without those that are specified above) ...nativeStyles, [vars['gap']]: formatSingleSpacingValue(gap) || 0, }; // Filter undefined values const rootStylesFiltered = filterObject(rootStyles, (key, value) => typeof value !== 'undefined'); return (React.createElement("div", { "data-hook": dataHook, className: rootClassNames, style: rootStylesFiltered, ref: ref }, children)); }); Box.displayName = 'Box'; Box.propTypes = { /** Allows to render any component as a child item */ children: PropTypes.node, /** Define styles through a classname */ className: PropTypes.string, /** Defines if the box behaves as an inline element */ inline: PropTypes.bool, /** Defines how the children are ordered (horizontally or vertically) */ direction: PropTypes.oneOf(Object.keys(directions)), /** Defines how the children are aligned according to the X axis */ align: PropTypes.oneOf(Object.keys(horizontalAlignmentValues)), /** Defines how the children are aligned according to the Y axis */ verticalAlign: PropTypes.oneOf(Object.keys(verticalAlignmentValues)), /** Sets the gaps/gutters between flex items. * Accepts a numeric value (multiplied by spacing unit), predefined spacing value (tiny, small, etc.) * a spacing token (SP1, SP2, etc.) */ gap: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), /** Sets padding on all sides. * Accepts a numeric value (multiplied by spacing unit), predefined spacing value (tiny, small, etc.) * a spacing token (SP1, SP2, etc.) or a string of space-separated values ("3px 3px") */ padding: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), /** Sets padding on the top. * Accepts a numeric value (multiplied by spacing unit), predefined spacing value (tiny, small, etc.) * a spacing token (SP1, SP2, etc.) or a value in pixels */ paddingTop: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), /** Sets padding on the right. * Accepts a numeric value (multiplied by spacing unit), predefined spacing value (tiny, small, etc.) * a spacing token (SP1, SP2, etc.) or a value in pixels */ paddingRight: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), /** Sets padding on the bottom. * Accepts a numeric value (multiplied by spacing unit), predefined spacing value (tiny, small, etc.) * a spacing token (SP1, SP2, etc.) or a value in pixels */ paddingBottom: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), /** Sets padding on the left. * Accepts a numeric value (multiplied by spacing unit), predefined spacing value (tiny, small, etc.) * a spacing token (SP1, SP2, etc.) or a value in pixels */ paddingLeft: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), /** Sets margin on all sides. * Accepts a numeric value (multiplied by spacing unit), predefined spacing value (tiny, small, etc.) * a spacing token (SP1, SP2, etc.) or a string of space-separated values ("3px 3px") */ margin: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), /** Sets margin on the top. * Accepts a numeric value (multiplied by spacing unit), predefined spacing value (tiny, small, etc.) * a spacing token (SP1, SP2, etc.) or a value in pixels */ marginTop: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), /** Sets margin on the right. * Accepts a numeric value (multiplied by spacing unit), predefined spacing value (tiny, small, etc.) * a spacing token (SP1, SP2, etc.) or a value in pixels */ marginRight: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), /** Sets margin on the bottom. * Accepts a numeric value (multiplied by spacing unit), predefined spacing value (tiny, small, etc.) * a spacing token (SP1, SP2, etc.) or a value in pixels */ marginBottom: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), /** Sets margin on the left. * Accepts a numeric value (multiplied by spacing unit), predefined spacing value (tiny, small, etc.) * a spacing token (SP1, SP2, etc.) or a value in pixels */ marginLeft: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), /** Sets the minimum width of the box in pixels */ minWidth: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), /** Sets the maximum width of the box in pixels */ maxWidth: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), /** Sets the width of the box in pixels */ width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), /** Sets the minimum height of the box in pixels */ minHeight: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), /** Sets the maximum height of the box in pixels */ maxHeight: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), /** Sets the height of the box in pixels */ height: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), /** Sets a text color by a key from the color palette or natively supported value (Hex, RGB, etc.) */ color: PropTypes.string, /** Sets a background color by a key from the color palette or natively supported value (Hex, RGB, etc.) */ backgroundColor: PropTypes.string, /** Sets a border color by a key from the color palette or natively supported value (Hex, RGB, etc.) */ borderColor: PropTypes.string, /** Sets a border top color by a key from the color palette or natively supported value (Hex, RGB, etc.) */ borderTopColor: PropTypes.string, /** Sets a border right color by a key from the color palette or natively supported value (Hex, RGB, etc.) */ borderRightColor: PropTypes.string, /** Sets a border bottom color by a key from the color palette or natively supported value (Hex, RGB, etc.) */ borderBottomColor: PropTypes.string, /** Sets a border left color by a key from the color palette or natively supported value (Hex, RGB, etc.) */ borderLeftColor: PropTypes.string, /** Accepts HTML attributes that can be used in the tests */ dataHook: PropTypes.string, }; export default Box; //# sourceMappingURL=Box.js.map