UNPKG

wix-style-react

Version:
249 lines (212 loc) • 7.03 kB
import React from 'react'; import PropTypes from 'prop-types'; import { st, classes } from './Thumbnail.st.css'; import CheckboxChecked from 'wix-ui-icons-common/system/CheckboxChecked'; import Text from '../Text'; import { withFocusable } from 'wix-ui-core/dist/src/hocs/Focusable/FocusableHOC'; import { dataHooks } from './constants'; import Box from '../Box'; import { FontUpgradeContext } from '../FontUpgrade/context'; const isString = a => typeof a === 'string'; /** * # Thumbnail * Component for showing thumbnails * * It takes full space of parent component, works well together with `<Proportion/>` * */ class Thumbnail extends React.PureComponent { static displayName = 'Thumbnail'; static propTypes = { /** Applies a data-hook HTML attribute that can be used in the tests. */ dataHook: PropTypes.string, /** Specifies a CSS class name to be appended to the component’s root element. */ className: PropTypes.string, /** Renders specified children items inside of the thumbnail. Accepts any kind of content. When passed, title will be rendered below a thumbnail. */ children: PropTypes.node, /** Sets the title of a thumbnail. */ title: PropTypes.node, /** Sets thumbnail description. */ description: PropTypes.node, /** Specifies an image to be displayed inside of a thumbnail. * If given as string, it will be used within `<img/>`. * Otherwise can be given as React.Node */ image: PropTypes.node, /** Controls the size of a thumbnail. */ size: PropTypes.oneOf(['tiny', 'small', 'medium']), /** Specifies whether a thumbnail is selected. */ selected: PropTypes.bool, /** Specifies whether thumbnail interactions are disabled. */ disabled: PropTypes.bool, /** Hides a checkmark icon that indicates selected thumbnail. Selected option will be highlighted with border only. */ hideSelectedIcon: PropTypes.bool, /** Render image as a background of a thumbnail. As a result, title is rendered below the image thumbnail. */ backgroundImage: PropTypes.node, /** Defines a callback function which is called every time a thumbnail is clicked. */ onClick: PropTypes.func, /** Controls the width of a thumbnail. */ width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), /** Controls the height of a thumbnail. */ height: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), /** Controls vertical alignment of content. */ contentAlignment: PropTypes.oneOf(['top', 'center']), }; static defaultProps = { size: 'medium', selected: false, disabled: false, contentAlignment: 'center', }; _renderBottomTitle = () => { const { size, title, selected, disabled } = this.props; return ( <Box align="center"> <Text className={st(classes.bottomTitle, { selected, disabled })} dataHook={dataHooks.thumbnailBottomTitle} size={size} tagName="div" weight="thin" ellipsis children={title} /> </Box> ); }; _renderBackgroundLayout = () => { const { disabled } = this.props; return isString(this.props.backgroundImage) ? ( <div className={st(classes.backgroundImage, { disabled })} data-hook={dataHooks.thumbnailBackgroundImage} style={{ backgroundImage: `url(${this.props.backgroundImage})` }} /> ) : ( this.props.backgroundImage ); }; _renderNoBackgroundLayout = () => { const { title, description, image, size, disabled } = this.props; return ( <div> {image && ( <div className={classes.image} data-hook={dataHooks.thumbnailImage} children={isString(image) ? <img src={image} /> : image} /> )} {title && ( <FontUpgradeContext.Consumer> {({ active }) => ( <Text className={classes.title} dataHook={dataHooks.thumbnailTitle} size={size} tagName="div" weight={active && size === 'tiny' ? 'bold' : 'normal'} children={title} skin={disabled ? 'disabled' : undefined} /> )} </FontUpgradeContext.Consumer> )} {description && ( <Text className={classes.description} dataHook={dataHooks.thumbnailDescription} size={size} weight="thin" tagName="div" secondary children={description} skin={disabled ? 'disabled' : undefined} /> )} </div> ); }; _renderThumbnailContent = () => { const { backgroundImage, children, disabled } = this.props; const hasBackground = !!backgroundImage; const hasChildren = !!children; if (hasChildren) { return ( <div className={st(classes.customChild, { disabled })}>{children}</div> ); } if (hasBackground) { return this._renderBackgroundLayout(); } return this._renderNoBackgroundLayout(); }; _renderSelectedIcon = () => ( <div className={classes.selectedIcon} data-hook={dataHooks.thumbnailSelectedIcon} > <CheckboxChecked height="7.8" width="10" /> </div> ); _onKeyDown = event => [13 /* enter */, 32 /* space */].some(key => event.keyCode === key) && this.props.onClick(event); render() { const { children, dataHook, size, selected, disabled, title, backgroundImage, onClick, hideSelectedIcon, width, height, contentAlignment, focusableOnFocus, focusableOnBlur, className, } = this.props; const hasChildren = !!children; const hasBackground = !!backgroundImage; const showBottomTitle = (hasChildren || hasBackground) && title; return ( <div style={{ width }} className={st(classes.root, { disabled })} onClick={disabled ? null : onClick} onKeyDown={disabled ? null : this._onKeyDown} data-hook={dataHook} > <div style={{ height }} className={st( classes.thumbnail, { selected, disabled, size, hasBackground, hasChildren, contentAlignment, }, className, )} data-selected={selected} data-disabled={disabled} onFocus={focusableOnFocus} onBlur={focusableOnBlur} tabIndex={disabled ? null : 0} data-hook={dataHooks.thumbnailWrapper} > {!hideSelectedIcon && selected && this._renderSelectedIcon()} {this._renderThumbnailContent()} </div> {showBottomTitle ? this._renderBottomTitle() : null} </div> ); } } export default withFocusable(Thumbnail);