UNPKG

@shopify/polaris

Version:

Shopify’s admin product component library

127 lines (121 loc) 4.53 kB
'use strict'; var React = require('react'); var css = require('../../utilities/css.js'); var useIsAfterInitialMount = require('../../utilities/use-is-after-initial-mount.js'); var Avatar_module = require('./Avatar.css.js'); var hooks = require('../../utilities/i18n/hooks.js'); var Image = require('../Image/Image.js'); var Status = /*#__PURE__*/function (Status) { Status["Pending"] = "PENDING"; Status["Loaded"] = "LOADED"; Status["Errored"] = "ERRORED"; return Status; }(Status || {}); const STYLE_CLASSES = ['one', 'two', 'three', 'four', 'five', 'six', 'seven']; const avatarStrokeWidth = { xs: '3', sm: '2.5', md: '2.5', lg: '2.5', xl: '2' }; /** * Computes a rudimentary hash from a string by xoring the character codes * of all characters */ function xorHash(str) { let hash = 0; for (const char of str) { hash ^= char.charCodeAt(0); } return hash; } function styleClass(name) { return name ? STYLE_CLASSES[xorHash(name) % STYLE_CLASSES.length] : STYLE_CLASSES[0]; } function Avatar({ name, source, onError, initials, customer, size = 'md', accessibilityLabel }) { const i18n = hooks.useI18n(); const isAfterInitialMount = useIsAfterInitialMount.useIsAfterInitialMount(); const [status, setStatus] = React.useState(Status.Pending); // If the source changes, set the status back to pending React.useEffect(() => { setStatus(Status.Pending); }, [source]); const handleError = React.useCallback(() => { setStatus(Status.Errored); if (onError) { onError(); } }, [onError]); const handleLoad = React.useCallback(() => { setStatus(Status.Loaded); }, []); const hasImage = source && status !== Status.Errored; const nameString = name || initials; let label; if (accessibilityLabel) { label = accessibilityLabel; } else if (name) { label = name; } else if (initials) { const splitInitials = initials.split('').join(' '); label = i18n.translate('Polaris.Avatar.labelWithInitials', { initials: splitInitials }); } const className = css.classNames(Avatar_module.default.Avatar, size && Avatar_module.default[css.variationName('size', size)], hasImage && status === Status.Loaded && Avatar_module.default.imageHasLoaded, !customer && !hasImage && Avatar_module.default[css.variationName('style', styleClass(nameString))]); const textClassName = css.classNames(Avatar_module.default.Text, (initials?.length || 0) > 2 && Avatar_module.default.long); const imageClassName = css.classNames(Avatar_module.default.Image, status !== Status.Loaded && Avatar_module.default.hidden); const imageMarkUp = source && isAfterInitialMount && status !== Status.Errored ? /*#__PURE__*/React.createElement(Image.Image, { className: imageClassName, source: source, alt: "", role: "presentation", onLoad: handleLoad, onError: handleError }) : null; // Use `dominant-baseline: central` instead of `dy` when Edge supports it. const verticalOffset = '0.35em'; const avatarPath = /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("path", { fill: "none", d: "M25.5 13.5C25.5 16.5376 23.0376 19 20 19C16.9624 19 14.5 16.5376 14.5 13.5C14.5 10.4624 16.9624 8 20 8C23.0376 8 25.5 10.4624 25.5 13.5Z", stroke: "currentColor", strokeWidth: avatarStrokeWidth[size] }), /*#__PURE__*/React.createElement("path", { fill: "none", d: "M10.3433 29.682L9.47 31.254C9.03481 32.0373 9.60125 33 10.4974 33H29.5026C30.3988 33 30.9652 32.0373 30.53 31.254L29.6567 29.682C27.7084 26.175 24.0119 24 20 24C15.9882 24 12.2916 26.175 10.3433 29.682Z", stroke: "currentColor", strokeWidth: avatarStrokeWidth[size], strokeLinecap: "round", strokeLinejoin: "round" })); const avatarBody = customer || !initials ? avatarPath : /*#__PURE__*/React.createElement("text", { className: textClassName, x: "50%", y: "50%", dy: verticalOffset, fill: "currentColor", textAnchor: "middle" }, initials); const svgMarkup = hasImage ? null : /*#__PURE__*/React.createElement("span", { className: Avatar_module.default.Initials }, /*#__PURE__*/React.createElement("svg", { className: Avatar_module.default.Svg, viewBox: "0 0 40 40" }, avatarBody)); return /*#__PURE__*/React.createElement("span", { "aria-label": label, role: label ? 'img' : 'presentation', className: className }, svgMarkup, imageMarkUp); } exports.Avatar = Avatar; exports.STYLE_CLASSES = STYLE_CLASSES;