@hackplan/polaris
Version:
Shopify’s product component library
93 lines (92 loc) • 3.6 kB
JavaScript
import React from 'react';
import { classNames, variationName } from '../../utilities/css';
import { isServer } from '../../utilities/target';
import { withAppProvider } from '../AppProvider';
import Image from '../Image';
import styles from './Avatar.scss';
import * as avatars from './images';
const STYLE_CLASSES = ['one', 'two', 'three', 'four', 'five', 'six'];
const AVATAR_IMAGES = Object.keys(avatars).map(
// import/namespace does not allow computed values by default
// eslint-disable-next-line import/namespace
(key) => avatars[key]);
export class Avatar extends React.PureComponent {
constructor() {
super(...arguments);
this.state = {
hasError: false,
hasLoaded: false,
};
this.handleError = () => {
this.setState({ hasError: true, hasLoaded: false });
};
this.handleLoad = () => {
this.setState({ hasLoaded: true, hasError: false });
};
}
static getDerivedStateFromProps(props, state) {
if (props.source !== state.prevSource) {
return {
prevSource: props.source,
hasError: false,
hasLoaded: false,
};
}
return null;
}
render() {
const { name, source, initials, customer, size = 'medium', accessibilityLabel, polaris: { intl }, } = this.props;
const { hasError, hasLoaded } = this.state;
const hasImage = (source || customer) && !hasError;
const nameString = name || initials;
let finalSource;
let label;
if (accessibilityLabel) {
label = accessibilityLabel;
}
else if (name) {
label = name;
}
else if (initials) {
const splitInitials = initials.split('').join(' ');
label = intl.translate('Polaris.Avatar.labelWithInitials', {
initials: splitInitials,
});
}
else {
label = intl.translate('Polaris.Avatar.label');
}
if (source) {
finalSource = source;
}
else if (customer) {
finalSource = customerPlaceholder(nameString);
}
const className = classNames(styles.Avatar, styles[variationName('style', styleClass(nameString))], size && styles[variationName('size', size)], hasImage && !hasLoaded && styles.hidden, hasImage && styles.hasImage);
const imageMarkUp = finalSource && !isServer && !hasError ? (<Image className={styles.Image} source={finalSource} alt="" role="presentation" onLoad={this.handleLoad} onError={this.handleError}/>) : null;
// Use `dominant-baseline: central` instead of `dy` when Edge supports it.
const verticalOffset = '0.35em';
const initialsMarkup = initials && !hasImage ? (<span className={styles.Initials}>
<svg className={styles.Svg} viewBox="0 0 48 48">
<text x="50%" y="50%" dy={verticalOffset} fill="currentColor" fontSize="26" textAnchor="middle">
{initials}
</text>
</svg>
</span>) : null;
return (<span aria-label={label} role="img" className={className}>
{initialsMarkup}
{imageMarkUp}
</span>);
}
}
function styleClass(name) {
return name
? STYLE_CLASSES[name.charCodeAt(0) % STYLE_CLASSES.length]
: STYLE_CLASSES[0];
}
function customerPlaceholder(name) {
return name
? AVATAR_IMAGES[name.charCodeAt(0) % AVATAR_IMAGES.length]
: AVATAR_IMAGES[0];
}
export default withAppProvider()(Avatar);