Created
February 10, 2017 10:03
-
-
Save qrobin/0f598d17341a91da7f57b9817be9b830 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// (C) Copyright 2014-2016 Hewlett Packard Enterprise Development LP | |
import React, { Component, PropTypes } from 'react'; | |
import classnames from 'classnames'; | |
import CSSClassnames from '../utils/CSSClassnames'; | |
import Props from '../utils/Props'; | |
import Box from './Box'; | |
import Label from './Label'; | |
import Heading from './Heading'; | |
import Headline from './Headline'; | |
import Markdown from './Markdown'; | |
import Anchor from './Anchor'; | |
import Layer from './Layer'; | |
import Video from './Video'; | |
import CirclePlayIcon from './icons/base/CirclePlay'; | |
import Responsive from '../utils/Responsive'; | |
const CLASS_ROOT = CSSClassnames.CARD; | |
const LABEL_SIZES = { | |
xlarge: 'medium', | |
large: 'medium', | |
medium: 'medium', | |
small: 'medium', | |
xsmall: 'small' | |
}; | |
const HEADLINE_SIZES = { | |
xlarge: 'medium', | |
large: 'medium' | |
}; | |
const HEADING_TAGS = { | |
medium: 'h1', | |
small: 'h2', | |
xsmall: 'h3' | |
}; | |
const PARAGRAPH_SIZES = { | |
xlarge: 'xlarge', | |
large: 'xlarge', | |
medium: 'large', | |
small: 'large', | |
xsmall: 'medium' | |
}; | |
const PARAGRAPH_MARGINS = { | |
xlarge: 'large', | |
large: 'large', | |
medium: 'medium', | |
small: 'medium', | |
xsmall: 'small' | |
}; | |
export default class Card extends Component { | |
constructor(props) { | |
super(props); | |
this._onClick = this._onClick.bind(this); | |
this._onResponsive = this._onResponsive.bind(this); | |
this.state = { | |
activeVideo: false, | |
small: false | |
}; | |
} | |
componentDidMount() { | |
this._responsive = Responsive.start(this._onResponsive); | |
} | |
componentWillUnmount() { | |
if (this._responsive) { | |
this._responsive.stop(); | |
} | |
} | |
_onResponsive(small) { | |
this.setState({ | |
small: !!small | |
}); | |
} | |
_onClick(event) { | |
const {video} = this.props; | |
if (video) { | |
event.preventDefault(); | |
this.setState({ | |
activeVideo: !this.state.activeVideo | |
}); | |
} | |
} | |
_renderLabel() { | |
const {label, textSize} = this.props; | |
let result = label; | |
if (typeof label === 'string') { | |
result = ( | |
<Label size={ LABEL_SIZES[textSize] } margin="none" uppercase={ true }> | |
{ label } | |
</Label> | |
); | |
} | |
return result; | |
} | |
_renderHeading() { | |
const {heading, headingStrong, textSize} = this.props; | |
let result = heading; | |
if (typeof heading === 'string') { | |
if (HEADLINE_SIZES[textSize]) { | |
result = ( | |
<Headline size={ HEADLINE_SIZES[textSize] } strong={ headingStrong }> | |
{ heading } | |
</Headline> | |
); | |
} else { | |
result = ( | |
<Heading tag={ HEADING_TAGS[textSize] } strong={ headingStrong }> | |
{ heading } | |
</Heading> | |
); | |
} | |
} | |
return result; | |
} | |
_renderLink() { | |
const {link} = this.props; | |
return link; | |
} | |
_renderThumbnail() { | |
const {direction, thumbnail, video} = this.props; | |
const {small} = this.state; | |
let result = thumbnail; | |
if (typeof thumbnail === 'string') { | |
const size = small ? 'large' : 'xlarge'; | |
const videoIcon = (video) ? | |
( | |
<Anchor icon={ <CirclePlayIcon responsive={ false } colorIndex="brand" size={ size } /> } /> | |
) : | |
undefined; | |
const flex = 'row' === direction ? 'grow' : undefined; | |
result = ( | |
<Box className={ `${CLASS_ROOT}__thumbnail` } flex={ flex } backgroundImage={ `url(${thumbnail})` } basis="small" justify="center" align="center"> | |
{ videoIcon } | |
</Box> | |
); | |
} | |
return result; | |
} | |
_renderVideoLayer() { | |
const {video} = this.props; | |
const {activeVideo} = this.state; | |
let result; | |
if (video && activeVideo) { | |
let layerContent; | |
if (video.source) { | |
layerContent = ( | |
<Video> | |
<source src={ video.source } type={ `video/${video.type}` } /> | |
</Video> | |
); | |
} else { | |
layerContent = video; | |
} | |
result = ( | |
<Layer onClose={ this._onClick } closer={ true } flush={ true }> | |
{ layerContent } | |
</Layer> | |
); | |
} | |
return result; | |
} | |
_renderDescription() { | |
const {description, textSize} = this.props; | |
let result = description; | |
if (typeof description === 'string') { | |
const components = { | |
p: { | |
props: { | |
margin: PARAGRAPH_MARGINS[textSize], | |
size: PARAGRAPH_SIZES[textSize] | |
} | |
} | |
}; | |
result = <Markdown components={ components } content={ description } />; | |
} | |
return result; | |
} | |
render() { | |
const {a11yTitle, children, className, contentPad, onClick, reverse, truncate} = this.props; | |
const boxProps = Props.pick(this.props, Object.keys(Box.propTypes)); | |
const restProps = Props.omit(this.props, Object.keys(Card.propTypes)); | |
const classes = classnames( | |
CLASS_ROOT, | |
{ | |
[`${CLASS_ROOT}--selectable`]: (onClick) | |
}, | |
className | |
); | |
let thumbnail = this._renderThumbnail(); | |
let label = this._renderLabel(); | |
let heading = this._renderHeading(); | |
let description = this._renderDescription(); | |
let link = this._renderLink(); | |
let videoLayer = this._renderVideoLayer(); | |
const contentClasses = classnames( | |
{ | |
[`${CLASS_ROOT}__content`]: true, | |
[`${CLASS_ROOT}__content--truncate`]: truncate | |
} | |
); | |
const basis = 'row' === this.props.direction ? '2/3' : undefined; | |
const text = ( | |
<Box className={ contentClasses } pad={ contentPad } basis={ basis }> | |
{ label } | |
{ heading } | |
{ description } | |
{ children } | |
{ link } | |
</Box> | |
); | |
let cardJustify; | |
if (reverse) { | |
// align thumbnail to bottom/right of card for bottom cardPlacement | |
cardJustify = 'between'; | |
} | |
if (!this.props.size) { | |
if (this.props.direction === 'row') { | |
boxProps.size = { | |
width: 'xlarge' | |
}; | |
} else { | |
boxProps.size = { | |
width: 'medium' | |
}; | |
} | |
} | |
console.log(Card); | |
return ( | |
<Box {...boxProps} {...restProps} className={ classes } wrap={ true } justify={ cardJustify } onClick={ onClick } a11yTitle={ a11yTitle }> | |
{ thumbnail } | |
{ text } | |
{ videoLayer } | |
</Box> | |
); | |
} | |
} | |
; | |
Card.propTypes = { | |
contentPad: Box.propTypes.pad, | |
description: PropTypes.oneOfType([ | |
PropTypes.string, | |
PropTypes.element | |
]), | |
heading: PropTypes.oneOfType([ | |
PropTypes.string, | |
PropTypes.element | |
]), | |
headingStrong: PropTypes.bool, | |
label: PropTypes.oneOfType([ | |
PropTypes.string, | |
PropTypes.element | |
]), | |
link: PropTypes.element, | |
textSize: PropTypes.oneOf(['xsmall', 'small', 'medium', 'large', 'xlarge']), | |
thumbnail: PropTypes.oneOfType([ | |
PropTypes.string, | |
PropTypes.element | |
]), | |
truncate: PropTypes.bool, | |
video: PropTypes.oneOfType([ | |
PropTypes.shape({ | |
source: PropTypes.string.isRequired, | |
type: PropTypes.string | |
}), | |
PropTypes.element | |
]), | |
...Box.propTypes | |
}; | |
Card.defaultProps = { | |
a11yTitle: 'Card', | |
contentPad: 'medium', | |
headingStrong: true, | |
textSize: 'small' | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment