UNPKG

@dialpad/dialtone

Version:

Dialpad's Dialtone design system monorepo

314 lines (313 loc) 9.66 kB
import { getUniqueString, getRandomElement } from "../../common/utils.js"; import { AVATAR_SIZE_MODIFIERS, AVATAR_PRESENCE_STATES, AVATAR_GROUP_VALIDATOR, AVATAR_KIND_MODIFIERS, AVATAR_PRESENCE_SIZE_MODIFIERS, AVATAR_ICON_SIZES, AVATAR_RANDOM_COLORS } from "./avatar_constants.js"; import { ICON_SIZE_MODIFIERS } from "../icon/icon_constants.js"; import { extractInitialsFromName } from "./utils.js"; import normalizeComponent from "../../_virtual/_plugin-vue2_normalizer.js"; import DtPresence from "../presence/presence.vue.js"; const _sfc_main = { name: "DtAvatar", components: { DtPresence }, inheritAttrs: false, props: { /** * Id of the avatar content wrapper element */ id: { type: String, default() { return getUniqueString(); } }, /** * Pass in a seed to get the random color generation based on that string. For example if you pass in a * user ID as the string it will return the same randomly generated colors every time for that user. */ seed: { type: String, default: void 0 }, /** * Set the avatar background to a specific color. If undefined will randomize the color which can be deterministic * if the seed prop is set. */ color: { type: String, default: void 0 }, /** * The size of the avatar * @values xs, sm, md, lg, xl */ size: { type: String, default: "md", validator: (size) => Object.keys(AVATAR_SIZE_MODIFIERS).includes(size) }, /** * Used to customize the avatar container */ avatarClass: { type: [String, Array, Object], default: "" }, /** * Set classes on the avatar canvas. Wrapper around the core avatar image. */ canvasClass: { type: [String, Array, Object], default: "" }, /** * Pass through classes. Used to customize the avatar icon */ iconClass: { type: [String, Array, Object], default: "" }, /** * Determines whether to show the presence indicator for * Avatar - accepts PRESENCE_STATES values: 'busy', 'away', 'offline', * or 'active'. By default, it's null and nothing is shown. * @values null, busy, away, offline, active */ presence: { type: String, default: AVATAR_PRESENCE_STATES.NONE, validator: (state) => { return Object.values(AVATAR_PRESENCE_STATES).includes(state); } }, /** * A set of props to be passed into the presence component. */ presenceProps: { type: Object, default: () => ({}) }, /** * Determines whether to show a group avatar. * Limit to 2 digits max, more than 99 will be rendered as “99+”. * if the number is 1 or less it would just show the regular avatar as if group had not been set. */ group: { type: Number, default: void 0, validator: (group) => AVATAR_GROUP_VALIDATOR(group) }, /** * The text that overlays the avatar */ overlayText: { type: String, default: "" }, /** * Used to customize the avatar overlay */ overlayClass: { type: [String, Array, Object], default: "" }, /** * Source of the image */ imageSrc: { type: String, default: "" }, /** * Alt attribute of the image, required if imageSrc is provided. * Can be set to '' (empty string) if the image is described * in text nearby */ imageAlt: { type: String, default: void 0 }, /** * Icon size to be displayed on the avatar * @values 100, 200, 300, 400, 500, 600, 700, 800 */ iconSize: { type: String, default: "", validator: (size) => !size || Object.keys(ICON_SIZE_MODIFIERS).includes(size) }, /** * Full name used to extract initials. */ fullName: { type: String, default: "" }, /** * Makes the avatar focusable and clickable, * emits a click event when clicked. */ clickable: { type: Boolean, default: false }, /** * Descriptive label for the icon. * To avoid a11y issues, set this prop if clickable and iconName are set. */ iconAriaLabel: { type: String, default: void 0 } }, emits: [ /** * Avatar click event * * @event click * @type {PointerEvent | KeyboardEvent} */ "click" ], data() { return { AVATAR_SIZE_MODIFIERS, AVATAR_KIND_MODIFIERS, AVATAR_PRESENCE_SIZE_MODIFIERS, AVATAR_ICON_SIZES, imageLoadedSuccessfully: null, formattedInitials: "", initializing: false }; }, computed: { hasOverlayIcon() { return !!this.$slots.overlayIcon; }, iconDataQa() { return "dt-avatar-icon"; }, avatarClasses() { return [ "d-avatar", AVATAR_SIZE_MODIFIERS[this.validatedSize], this.avatarClass, { "d-avatar--group": this.showGroup, [`d-avatar--color-${this.getColor()}`]: !this.isIconType(), "d-avatar--clickable": this.clickable } ]; }, overlayClasses() { return [ "d-avatar__overlay", this.overlayClass, { "d-avatar__overlay-icon": this.hasOverlayIcon } ]; }, showGroup() { return AVATAR_GROUP_VALIDATOR(this.group); }, formattedGroup() { return this.group > 99 ? "99+" : this.group; }, validatedSize() { return this.group ? "xs" : this.size; }, showImage() { return this.imageLoadedSuccessfully !== false && this.imageSrc; } }, watch: { fullName: { immediate: true, handler() { this.formatInitials(); } }, size: { immediate: true, handler() { this.formatInitials(); } }, group: { immediate: true, handler() { this.formatInitials(); } }, imageSrc(newSrc) { this.imageLoadedSuccessfully = null; if (!newSrc) return; this.validateProps(); this.setImageListeners(); } }, mounted() { this.validateProps(); this.setImageListeners(); }, methods: { isIconType() { return this.$scopedSlots.icon && this.$scopedSlots.icon(); }, async setImageListeners() { await this.$nextTick(); const el = this.$refs.avatarImage; if (!el) return; el.addEventListener("load", () => this._loadedImageEventHandler(el), { once: true }); el.addEventListener("error", () => this._erroredImageEventHandler(el), { once: true }); }, formatInitials() { const initials = extractInitialsFromName(this.fullName); if (this.validatedSize === "xs") { this.formattedInitials = ""; } else if (this.validatedSize === "sm") { this.formattedInitials = initials[0]; } else { this.formattedInitials = initials; } }, getColor() { return this.color ?? getRandomElement(AVATAR_RANDOM_COLORS, this.seed); }, _loadedImageEventHandler(el) { this.imageLoadedSuccessfully = true; el.classList.remove("d-d-none"); }, _erroredImageEventHandler(el) { this.imageLoadedSuccessfully = false; el.classList.add("d-d-none"); }, validateProps() { if (this.imageSrc && this.imageAlt === void 0) { console.error('image-alt required if image-src is provided. Can be set to "" (empty string) if the image is described in text nearby'); } }, handleClick(e) { if (!this.clickable) return; this.$emit("click", e); } } }; var _sfc_render = function render() { var _vm = this, _c = _vm._self._c; return _c(_vm.clickable ? "button" : "div", { tag: "component", class: _vm.avatarClasses, attrs: { "id": _vm.id, "data-qa": "dt-avatar" }, on: { "click": _vm.handleClick } }, [_c("div", { ref: "canvas", class: [ _vm.canvasClass, "d-avatar__canvas", { "d-avatar--image-loaded": _vm.imageLoadedSuccessfully } ] }, [_vm.showImage ? _c("img", { ref: "avatarImage", staticClass: "d-avatar__image", attrs: { "data-qa": "dt-avatar-image", "src": _vm.imageSrc, "alt": _vm.imageAlt } }) : _vm.isIconType() ? _c("div", { class: [_vm.iconClass, _vm.AVATAR_KIND_MODIFIERS.icon], attrs: { "aria-label": _vm.clickable ? _vm.iconAriaLabel : "", "data-qa": _vm.iconDataQa, "role": _vm.clickable ? "button" : "" } }, [_vm._t("icon", null, { "iconSize": _vm.iconSize || _vm.AVATAR_ICON_SIZES[_vm.size] })], 2) : _c("span", { class: [_vm.AVATAR_KIND_MODIFIERS.initials] }, [_vm._v(" " + _vm._s(_vm.formattedInitials) + " ")])]), _vm.hasOverlayIcon || _vm.overlayText ? _c("div", { class: _vm.overlayClasses }, [_vm.hasOverlayIcon ? _vm._t("overlayIcon") : _vm.overlayText ? _c("p", { staticClass: "d-avatar__overlay-text" }, [_vm._v(" " + _vm._s(_vm.overlayText) + " ")]) : _vm._e()], 2) : _vm._e(), _vm.showGroup ? _c("span", { staticClass: "d-avatar__count", attrs: { "data-qa": "dt-avatar-count" } }, [_vm._v(_vm._s(_vm.formattedGroup))]) : _vm._e(), _vm.presence && !_vm.showGroup ? _c("dt-presence", _vm._b({ class: [ "d-avatar__presence", _vm.AVATAR_PRESENCE_SIZE_MODIFIERS[_vm.size] ], attrs: { "presence": _vm.presence, "data-qa": "dt-presence" } }, "dt-presence", _vm.presenceProps, false)) : _vm._e()], 1); }; var _sfc_staticRenderFns = []; var __component__ = /* @__PURE__ */ normalizeComponent( _sfc_main, _sfc_render, _sfc_staticRenderFns ); const DtAvatar = __component__.exports; export { DtAvatar as default }; //# sourceMappingURL=avatar.vue.js.map