wix-style-react
Version:
217 lines (196 loc) • 6.58 kB
JavaScript
import React from 'react';
import PropTypes from 'prop-types';
import { WixStyleReactContext } from '../WixStyleReactProvider/context';
import Content from './components/Content';
import { Layout, Cell } from '../Layout';
import Proportion from '../Proportion';
import { SIZES, DIRECTIONS } from './constants';
import { st, classes } from './MarketingLayout.st.css';
import { stVars as colorsStVars } from '../Foundation/stylable/colors.st.css';
import deprecationLog from '../utils/deprecationLog';
const cellSpansBySize = {
[SIZES.tiny]: {
image: 4,
content: 8,
},
[SIZES.small]: {
image: 3,
spacer: 1,
content: 8,
},
[SIZES.medium]: {
image: 4,
spacer: 1,
content: 7,
},
[SIZES.large]: {
image: 5,
spacer: 1,
content: 6,
},
};
const imagePlaceholderAspectRatioBySize = {
[SIZES.tiny]: 1,
[SIZES.small]: 1,
[SIZES.medium]: 282 / 188,
[SIZES.large]: 360 / 240,
};
/** Marketing layout is a layout designed to promote new features or display first time visit.
* Component has title, description, action and illustration areas. */
class MarketingLayout extends React.PureComponent {
static displayName = 'MarketingLayout';
static propTypes = {
/** Applies a data-hook HTML attribute that can be used in the tests. */
dataHook: PropTypes.string,
/** Accepts image URL or a custom element to be displayed on the side of content. */
image: PropTypes.node,
/** Specifies image area background color. Can be a keyword from color palette or any supported CSS color value (HEX, RGB, etc.). */
imageBackgroundColor: PropTypes.string,
/**
* Controls the size of the marketing layout.<br/>
* Large size will be deprecated in the next major version.
*/
size: PropTypes.oneOf(['tiny', 'small', 'medium', 'large']),
/** Controls content direction. */
direction: PropTypes.oneOf(['horizontal', 'vertical']),
/** Controls the vertical alignment of the content. */
alignItems: PropTypes.oneOf(['center', 'stretch']),
/** Flips content layout. If true, image will be displayed on the left side of the content. */
inverted: PropTypes.bool,
/** Sets marketing layout actions. Accepts single or multiple interactive components. Most commonly contain `<Button/>` or `<TextButton/>`. */
actions: PropTypes.node,
/** Sets the marketing layout title. Accepts text string or a custom element. */
title: PropTypes.node,
/** Sets the marketing layout description. Accepts text string or a custom element. */
description: PropTypes.node,
/** Adds a container for a `<Badge/>` component at the top left corner. Affect component height. */
badge: PropTypes.node,
/** Specifies whether the badge is hidden. Can be used to add additional vertical spacing, if no badge is given. */
hiddenBadge: PropTypes.bool,
};
static defaultProps = {
size: 'small',
alignItems: 'center',
inverted: false,
direction: 'horizontal',
hiddenBadge: false,
};
_renderSpacerCell = span => <Cell key="spacer" span={span} />;
_renderImagePlaceholder = () => {
const { size } = this.props;
return (
<Proportion aspectRatio={imagePlaceholderAspectRatioBySize[size]}>
<div className={classes.imagePlaceholder} />
</Proportion>
);
};
_renderImageCell = span => {
const { image, imageBackgroundColor } = this.props;
return (
<Cell key="image" span={span}>
<div className={classes.imageWrapper}>
{imageBackgroundColor && (
<div
className={classes.imageBackground}
style={{
backgroundColor:
colorsStVars[imageBackgroundColor] || imageBackgroundColor,
}}
/>
)}
<div className={classes.imageContainer}>
{typeof image === 'string' ? (
<img src={image} width="100%" />
) : (
image || this._renderImagePlaceholder()
)}
</div>
</div>
</Cell>
);
};
_renderContentCell = span => {
const { size, actions, title, description, badge, hiddenBadge } =
this.props;
return (
<Cell key="content" span={span}>
{badge && !hiddenBadge && <div className={classes.badge}>{badge}</div>}
<Content
size={size}
actions={actions}
title={title}
description={description}
badge={badge}
/>
</Cell>
);
};
_renderContent = () => {
const { direction, size } = this.props;
const isVertical = direction === DIRECTIONS.vertical;
return (
<Layout gap={size === SIZES.tiny ? '24px' : '30px'}>
{isVertical
? this._renderVerticalCells()
: this._renderHorizontalCells()}
</Layout>
);
};
_renderHorizontalCells() {
const { inverted, size } = this.props;
const { image, spacer, content } = cellSpansBySize[size];
const contentCell = this._renderContentCell(content);
const spacerCell = size !== SIZES.tiny && this._renderSpacerCell(spacer);
const imageCell = this._renderImageCell(image);
return inverted
? [imageCell, contentCell, spacerCell]
: [contentCell, spacerCell, imageCell];
}
_renderVerticalCells() {
const { inverted, image } = this.props;
const imageCell = image && this._renderImageCell(12);
const contentCell = this._renderContentCell(12);
return inverted ? [contentCell, imageCell] : [imageCell, contentCell];
}
render() {
const {
size,
badge,
hiddenBadge,
alignItems,
inverted,
actions,
dataHook,
imageBackgroundColor,
direction,
} = this.props;
if (size === SIZES.large) {
deprecationLog(
`<MarketingLayout/> size large wil be deprecated in the next major version`,
);
}
return (
<WixStyleReactContext.Consumer>
{({ reducedSpacingAndImprovedLayout }) => (
<div
className={st(classes.root, {
size,
badge: !!badge,
hiddenBadge,
alignItems,
inverted,
withActions: !!actions,
withImageBackground: !!imageBackgroundColor,
reducedSpacingAndImprovedLayout,
direction,
})}
data-hook={dataHook}
>
{this._renderContent()}
</div>
)}
</WixStyleReactContext.Consumer>
);
}
}
export default MarketingLayout;