wix-style-react
Version:
wix-style-react
145 lines • 7.74 kB
JavaScript
import React from 'react';
import PropTypes from 'prop-types';
import IconButton from '../IconButton';
import { avatarShapes, dataHooks } from './constants';
import { WixStyleReactContext } from '../WixStyleReactProvider/context';
import Loader from '../Loader';
import { placeholderSVGs } from './assets';
import { st, classes } from './Avatar.st.css';
import { capitalize } from '../utils/cssClassUtils';
import stringToColor from './string-to-color';
import AvatarCore from './AvatarCore';
const getSizeNumber = size => Number(size.substring(4));
const defaultSize = 48;
const minSmallIconButton = 60;
/**
* Avatar is a type of element that visually represents a user, either as an image, name initials or placeholder icon.
*/
class Avatar extends React.PureComponent {
constructor(props) {
super(props);
this._onMouseEnter = () => {
if (this.props.showIndicationOnHover) {
this.setState({ showIndication: true });
}
};
this._onMouseLeave = () => {
if (this.props.showIndicationOnHover) {
this.setState({ fadeIndication: true });
setTimeout(() => this.setState({ fadeIndication: false, showIndication: false }), 150);
}
};
this.state = {
fadeIndication: false,
showIndication: false,
};
}
render() {
const { size, presence, indication, color, customIndication, onIndicationClick, dataHook, className, shape, text, placeholder, name, onClick, showIndicationOnHover, loading, ...rest } = this.props;
const { fadeIndication, showIndication } = this.state;
const calculatedColor = color || stringToColor(text || name); // if color is provided as a prop use it, otherwise, generate a color based on the text
const sizeNumber = getSizeNumber(size);
const renderOnHover = !showIndicationOnHover || showIndication;
const indicationConstraints = renderOnHover && sizeNumber >= defaultSize;
const renderIndication = indicationConstraints && !customIndication && indication;
const renderCustomIndication = indicationConstraints && customIndication;
const renderLoader = loading && sizeNumber >= defaultSize;
return (React.createElement(WixStyleReactContext.Consumer, null, ({ newColorsBranding }) => (React.createElement("div", { "data-hook": dataHook, className: st(className, classes.root) },
React.createElement("div", { "data-hook": dataHooks.avatarWSR, onMouseEnter: this._onMouseEnter, onMouseLeave: this._onMouseLeave, className: st(classes.avatarContainer, {
shape,
size,
indication: Boolean(customIndication || indication),
presence: Boolean(presence),
presenceType: presence,
clickable: !!onClick,
fade: fadeIndication,
hasText: !!text,
newColorsBranding,
}) },
React.createElement("div", { className: classes.coreAvatar },
React.createElement(AvatarCore, { ...rest, placeholder: placeholder ?? (React.createElement(AvatarDefaultPlaceholder, { shape: shape, size: size })), text: text, name: name, onClick: onClick, initialsLimit: sizeNumber < 30 ? 1 : undefined, "data-hook": dataHooks.avatarCore, className: st(classes.avatar, classes[`color${capitalize(calculatedColor)}`]) })),
renderLoader && [
React.createElement("div", { key: "overlay", className: st(classes.loaderContainer, classes.overlay) }),
React.createElement("div", { key: "loader", className: st(classes.loaderContainer, classes.loader) },
React.createElement(Loader, { dataHook: dataHooks.loader, size: "tiny" })),
],
presence && React.createElement("div", { className: classes.presence }),
renderIndication && (React.createElement("div", { className: classes.indication },
React.createElement(IconButton, { className: classes.iconButtonShadow, dataHook: dataHooks.indication, onClick: onIndicationClick, skin: "inverted", shape: shape, size: sizeNumber > minSmallIconButton ? 'small' : 'tiny' }, indication))),
renderCustomIndication && (React.createElement("div", { className: classes.indication, "data-hook": dataHooks.customIndication, onClick: onIndicationClick }, customIndication)))))));
}
}
const AvatarDefaultPlaceholder = ({ shape, size }) => shape !== avatarShapes.square
? placeholderSVGs[size][avatarShapes.circle]
: placeholderSVGs[size][avatarShapes.square];
const CoreAvatarPropTypes = {
/**
* Defines a name of the avatar user. Text initials will be generated from the name.
* The name value will be used as default value for HTML title and `aria-label` attributes.
* And also as default value for the image's alt attribute if `imgProps` is provided.
*/
name: PropTypes.string,
/** Defines a text to render as a content instead of a given `name`. */
text: PropTypes.string,
/**
* Accept any content to render as a content placeholder. This placeholder will be displayed if no text, name or imgProps are provided.<br>
* By default use a generic avatar user icon.
*/
placeholder: PropTypes.node,
/** Accept all common `<img>` tag properties. */
imgProps: PropTypes.object,
/** Defines a string that labels the current element in case where text label is not visible on the screen. */
ariaLabel: PropTypes.string,
/** Defines a standard HTML title attribute value. Applies it to the root element. */
title: PropTypes.string,
/** Defines a click event handler. When defined, component will be clickable and will have a pointer cursor on hover. */
onClick: PropTypes.func,
};
Avatar.displayName = 'Avatar';
Avatar.propTypes = {
...CoreAvatarPropTypes,
/** Controls the size of an avatar. */
size: PropTypes.oneOf([
'size90',
'size72',
'size60',
'size48',
'size36',
'size30',
'size24',
'size18',
]),
/**
* Controls the background color of the avatar. If not provided,
* color is determined by the provided text or name so that each name will receive a different color.
*/
color: PropTypes.oneOf(['A1', 'A2', 'A3', 'A4', 'A5', 'A6']),
/** Controls the shape of the image. */
shape: PropTypes.oneOf(['circle', 'square']),
/** Specifies a CSS class name to be appended to the component’s root element. */
className: PropTypes.string,
/** Applies a data-hook HTML attribute that can be used in the tests. */
dataHook: PropTypes.string,
/** Sets the presence status of an avatar. */
presence: PropTypes.oneOf(['online', 'offline', 'busy']),
/** Accept any content to render as an indication item. */
indication: PropTypes.node,
/**
* Accept any content to render as a custom indication item. This indication element will not be wrapped by an IconButton.
* It could be rendered in other shapes (such as square).
* */
customIndication: PropTypes.node,
/** Defines a callback function which is called every time indication element is clicked. */
onIndicationClick: PropTypes.func,
/** Shows indication element on hover. */
showIndicationOnHover: PropTypes.bool,
/** Shows a loader on top of an avatar. */
loading: PropTypes.bool,
};
Avatar.defaultProps = {
size: 'size48',
shape: 'circle',
showIndicationOnHover: false,
};
export default Avatar;
//# sourceMappingURL=Avatar.js.map