@nextcloud/vue
Version:
Nextcloud vue components
1 lines • 10.1 kB
Source Map (JSON)
{"version":3,"file":"NcUserBubble-DPAmU2_J.mjs","sources":["../../src/components/NcUserBubble/NcUserBubbleDiv.vue","../../src/components/NcUserBubble/NcUserBubble.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<template>\n\t<div>\n\t\t<slot name=\"trigger\" />\n\t</div>\n</template>\n","<!--\n - SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<docs>\n\n### General description\n\nThis component displays a user together with a small avatar in a grey bubble.\nIt's possible to use an actual user's avatar, just an image/icon as a url or an icon-class,\nto link the bubble to e.g. a users profile\nand to show a popover on hover with e.g. the full user name handle / email address or something else.\n\nThis component has the following slot:\n* a default slot which is for the content of the popover (this is passed to the popover component directly).\n\n### Examples\n\n```vue\n<p>\n\tSome text before <NcUserBubble user=\"admin\" display-name=\"Admin Example\" url=\"/test\">@admin@foreign-host.com</NcUserBubble> and after the bubble.\n\t<NcUserBubble avatar-image=\"icon-group\" display-name=\"test group xyz\" :primary=\"true\">Hey there!</NcUserBubble>\n</p>\n```\n\n### Example with name slot\n\n```vue\n<template>\n<NcUserBubble\n\t:size=\"34\"\n\tdisplay-name=\"Administrator\"\n\tuser=\"admin\">\n\t<template #name>\n\t\t<NcButton aria-label=\"Remove user\"\n\t\t\tvariant=\"tertiary-no-background\"\n\t\t\t@click=\"alert\">\n\t\t\t<template #icon>\n\t\t\t\t<NcIconSvgWrapper :path=\"mdiClose\" />\n\t\t\t</template>\n\t\t</NcButton>\n\t</template>\n</NcUserBubble>\n</template>\n<script>\nimport { mdiClose } from '@mdi/js'\n\nexport default {\n\tsetup() {\n\t\treturn {\n\t\t\tmdiClose,\n\t\t}\n\t},\n\tmethods: {\n\t\talert() {\n\t\t\talert('Removed')\n\t\t},\n\t},\n}\n</script>\n```\n\n</docs>\n\n<script setup lang=\"ts\">\nimport type { Slot } from 'vue'\nimport type { RouteLocation } from 'vue-router'\n\nimport { computed, warn, watch } from 'vue'\nimport { RouterLink } from 'vue-router'\nimport NcAvatar from '../NcAvatar/NcAvatar.vue'\nimport NcPopover from '../NcPopover/NcPopover.vue'\nimport NcUserBubbleDiv from './NcUserBubbleDiv.vue'\n\n/**\n * Default popover state. Requires the UserBubble\n * to have some content to render inside the popover\n */\nconst isOpen = defineModel<boolean>('open')\n\nconst props = withDefaults(defineProps<{\n\t/**\n\t * Override generated avatar, can be an url or an icon class\n\t */\n\tavatarImage?: string\n\n\t/**\n\t * Provide the user id if this is a user\n\t */\n\tuser?: string\n\n\t/**\n\t * Displayed label\n\t */\n\tdisplayName?: string\n\n\t/**\n\t * Whether or not to display the user-status\n\t */\n\tshowUserStatus?: boolean\n\n\t/**\n\t * Define the whole bubble as a link\n\t */\n\turl?: string\n\n\t/**\n\t * Use bubble as a router-link for in-app navigation\n\t */\n\tto?: RouteLocation\n\n\t/**\n\t * Use the primary colour\n\t */\n\tprimary?: boolean\n\n\t/**\n\t * This is the height of the component\n\t */\n\tsize?: number\n\n\t/**\n\t * This is the margin of the avatar (size - margin = avatar size)\n\t */\n\tmargin?: number\n}>(), {\n\tavatarImage: undefined,\n\tdisplayName: undefined,\n\tuser: undefined,\n\turl: undefined,\n\tto: undefined,\n\tmargin: 2,\n\tsize: 20,\n})\n\nconst emit = defineEmits<{\n\t/**\n\t * The mouse click event\n\t */\n\tclick: [event: MouseEvent]\n}>()\n\ndefineSlots<{\n\t/**\n\t * Main Popover content on userbubble hover/focus\n\t */\n\tdefault?: Slot\n\n\t/**\n\t * Optional slot just after the name\n\t */\n\tname?: Slot\n}>()\n\n/**\n * Is the provided avatar url valid or not\n */\nconst isAvatarUrl = computed(() => {\n\tif (!props.avatarImage) {\n\t\treturn false\n\t}\n\n\ttry {\n\t\tconst url = new URL(props.avatarImage)\n\t\treturn !!url\n\t} catch {\n\t\treturn false\n\t}\n})\n\n/**\n * Do we have a custom avatar or not\n */\nconst isCustomAvatar = computed(() => !!props.avatarImage)\n\nconst avatarStyle = computed(() => ({\n\tmarginInlineStart: `${props.margin}px`,\n}))\n\n/**\n * Is the URL prop set\n */\nconst hasUrl = computed(() => {\n\tif (!props.url || props.url.trim() === '') {\n\t\treturn false\n\t}\n\ttry {\n\t\tconst url = new URL(props.url, props.url?.startsWith?.('/') ? window.location.href : undefined)\n\t\treturn !!url\n\t} catch {\n\t\twarn('[NcUserBubble] Invalid URL passed', { url: props.url })\n\t\treturn false\n\t}\n})\n\n/**\n * href attribute to pass to content container\n */\nconst href = computed(() => hasUrl.value ? props.url : undefined)\n\nconst contentComponent = computed(() => {\n\tif (hasUrl.value) {\n\t\treturn 'a'\n\t} else if (props.to) {\n\t\treturn RouterLink\n\t} else {\n\t\treturn 'div'\n\t}\n})\n\nconst contentStyle = computed(() => ({\n\theight: `${props.size}px`,\n\tlineHeight: `${props.size}px`,\n\tborderRadius: `${props.size / 2}px`,\n}))\n\nwatch([() => props.displayName, () => props.user], () => {\n\tif (!props.displayName && !props.user) {\n\t\twarn('[NcUserBubble] At least `displayName` or `user` property should be set.')\n\t}\n})\n</script>\n\n<template>\n\t<component\n\t\t:is=\"!!$slots.default ? NcPopover : NcUserBubbleDiv\"\n\t\tv-model:shown=\"isOpen\"\n\t\tclass=\"user-bubble__wrapper\"\n\t\ttrigger=\"hover focus\">\n\t\t<!-- Main userbubble structure -->\n\t\t<template #trigger=\"{ attrs }\">\n\t\t\t<component\n\t\t\t\t:is=\"contentComponent\"\n\t\t\t\tclass=\"user-bubble__content\"\n\t\t\t\t:class=\"{ 'user-bubble__content--primary': primary }\"\n\t\t\t\t:style=\"contentStyle\"\n\t\t\t\t:to\n\t\t\t\t:href\n\t\t\t\tv-bind=\"attrs\"\n\t\t\t\t@click=\"emit('click', $event)\">\n\t\t\t\t<!-- NcAvatar -->\n\t\t\t\t<NcAvatar\n\t\t\t\t\t:url=\"isCustomAvatar && isAvatarUrl ? avatarImage : undefined\"\n\t\t\t\t\t:icon-class=\"isCustomAvatar && !isAvatarUrl ? avatarImage : undefined\"\n\t\t\t\t\t:user=\"user\"\n\t\t\t\t\t:display-name=\"displayName\"\n\t\t\t\t\t:size=\"size - (margin * 2)\"\n\t\t\t\t\t:style=\"avatarStyle\"\n\t\t\t\t\t:disable-tooltip=\"true\"\n\t\t\t\t\t:disable-menu=\"true\"\n\t\t\t\t\t:hide-status=\"!showUserStatus\"\n\t\t\t\t\tclass=\"user-bubble__avatar\" />\n\n\t\t\t\t<!-- Name -->\n\t\t\t\t<span class=\"user-bubble__name\">\n\t\t\t\t\t{{ displayName || user }}\n\t\t\t\t</span>\n\n\t\t\t\t<span v-if=\"!!$slots.name\" class=\"user-bubble__secondary\">\n\t\t\t\t\t<slot name=\"name\" />\n\t\t\t\t</span>\n\t\t\t</component>\n\t\t</template>\n\n\t\t<slot />\n\t</component>\n</template>\n\n<style lang=\"scss\" scoped>\n.user-bubble {\n\t&__wrapper {\n\t\t// align inline with text\n\t\tdisplay: inline-block;\n\t\tvertical-align: middle;\n\t\t// shrink and allow grow to fit\n\t\tmin-width: 0;\n\t\tmax-width: 100%;\n\t}\n\n\t&__content {\n\t\tdisplay: inline-flex;\n\t\tmax-width: 100%;\n\t\tbackground-color: var(--color-background-dark);\n\n\t\t&--primary {\n\t\t\tcolor: var(--color-primary-element-text);\n\t\t\tbackground-color: var(--color-primary-element);\n\t\t}\n\n\t\t> :last-child {\n\t\t\t// border radius end padding\n\t\t\tpadding-inline-end: 8px;\n\t\t}\n\t}\n\n\t&__avatar {\n\t\talign-self: center;\n\t}\n\n\t&__name {\n\t\toverflow: hidden;\n\t\twhite-space: nowrap;\n\t\ttext-overflow: ellipsis;\n\t}\n\n\t&__name,\n\t&__secondary {\n\t\t// proper spacing between avatar, name & slot\n\t\tpadding-block: 0;\n\t\tpadding-inline: 4px 0;\n\t}\n}\n</style>\n"],"names":["_createElementBlock","_renderSlot","_useModel","_openBlock","_createBlock","_resolveDynamicComponent","$slots","_withCtx","_mergeProps","primary","to","_createVNode","avatarImage","user","displayName","size","margin","showUserStatus","_createElementVNode","_toDisplayString"],"mappings":";;;;;;;sBAMCA,mBAEM,OAAA,MAAA;AAAA,IADLC,WAAuB,KAAA,QAAA,SAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;ACwEzB,UAAM,SAASC,SAAoB,SAAC,MAAM;AAE1C,UAAM,QAAQ;AAuDd,UAAM,OAAO;AAsBb,UAAM,cAAc,SAAS,MAAM;AAClC,UAAI,CAAC,MAAM,aAAa;AACvB,eAAO;AAAA,MACR;AAEA,UAAI;AACH,cAAM,MAAM,IAAI,IAAI,MAAM,WAAW;AACrC,eAAO,CAAC,CAAC;AAAA,MACV,QAAQ;AACP,eAAO;AAAA,MACR;AAAA,IACD,CAAC;AAKD,UAAM,iBAAiB,SAAS,MAAM,CAAC,CAAC,MAAM,WAAW;AAEzD,UAAM,cAAc,SAAS,OAAO;AAAA,MACnC,mBAAmB,GAAG,MAAM,MAAM;AAAA,IAAA,EACjC;AAKF,UAAM,SAAS,SAAS,MAAM;AAC7B,UAAI,CAAC,MAAM,OAAO,MAAM,IAAI,KAAA,MAAW,IAAI;AAC1C,eAAO;AAAA,MACR;AACA,UAAI;AACH,cAAM,MAAM,IAAI,IAAI,MAAM,KAAK,MAAM,KAAK,aAAa,GAAG,IAAI,OAAO,SAAS,OAAO,MAAS;AAC9F,eAAO,CAAC,CAAC;AAAA,MACV,QAAQ;AACP,aAAK,qCAAqC,EAAE,KAAK,MAAM,KAAK;AAC5D,eAAO;AAAA,MACR;AAAA,IACD,CAAC;AAKD,UAAM,OAAO,SAAS,MAAM,OAAO,QAAQ,MAAM,MAAM,MAAS;AAEhE,UAAM,mBAAmB,SAAS,MAAM;AACvC,UAAI,OAAO,OAAO;AACjB,eAAO;AAAA,MACR,WAAW,MAAM,IAAI;AACpB,eAAO;AAAA,MACR,OAAO;AACN,eAAO;AAAA,MACR;AAAA,IACD,CAAC;AAED,UAAM,eAAe,SAAS,OAAO;AAAA,MACpC,QAAQ,GAAG,MAAM,IAAI;AAAA,MACrB,YAAY,GAAG,MAAM,IAAI;AAAA,MACzB,cAAc,GAAG,MAAM,OAAO,CAAC;AAAA,IAAA,EAC9B;AAEF,UAAM,CAAC,MAAM,MAAM,aAAa,MAAM,MAAM,IAAI,GAAG,MAAM;AACxD,UAAI,CAAC,MAAM,eAAe,CAAC,MAAM,MAAM;AACtC,aAAK,yEAAyE;AAAA,MAC/E;AAAA,IACD,CAAC;;AAIA,aAAAC,UAAA,GAAAC,YAyCYC,0BAxCJC,KAAAA,OAAO,UAAU,YAAY,eAAe,GAAA;AAAA,QAC3C,OAAO,OAAA;AAAA,gEAAA,OAAM,QAAA;AAAA,QACrB,OAAM;AAAA,QACN,SAAQ;AAAA,MAAA;QAEG,SAAOC,QACjB,CA8BY,EA/BS,YAAK;AAAA,wBAC1BH,YA8BYC,wBA7BN,iBAAA,KAAgB,GADtBG,WA8BY;AAAA,YA5BX,OAAK,CAAC,wBAAsB,EAAA,iCACeC,KAAAA,SAAO;AAAA,YACjD,OAAO,aAAA;AAAA,YACP,IAAAC,KAAAA;AAAAA,YACA,MAAA,KAAA;AAAA,UAAA,GACO,OAAK;AAAA,YACZ,SAAK,OAAA,CAAA,MAAA,OAAA,CAAA,IAAA,CAAA,WAAE,KAAI,SAAU,MAAM;AAAA,UAAA;6BAE5B,MAU+B;AAAA,cAV/BC,YAU+B,UAAA;AAAA,gBAT7B,KAAK,eAAA,SAAkB,oBAAcC,KAAAA,cAAc;AAAA,gBACnD,cAAY,eAAA,SAAc,CAAK,oBAAcA,KAAAA,cAAc;AAAA,gBAC3D,MAAMC,KAAAA;AAAAA,gBACN,gBAAcC,KAAAA;AAAAA,gBACd,MAAMC,KAAAA,OAAQC,KAAAA,SAAM;AAAA,gBACpB,sBAAO,YAAA,KAAW;AAAA,gBAClB,mBAAiB;AAAA,gBACjB,gBAAc;AAAA,gBACd,gBAAcC,KAAAA;AAAAA,gBACf,OAAM;AAAA,cAAA;cAGPC,mBAEO,QAFP,YAEOC,gBADHL,KAAAA,eAAeD,KAAAA,IAAI,GAAA,CAAA;AAAA,cAGTP,CAAAA,CAAAA,KAAAA,OAAO,QAArBH,UAAA,GAAAH,mBAEO,QAFP,YAEO;AAAA,gBADNC,WAAoB,KAAA,QAAA,QAAA,CAAA,GAAA,QAAA,IAAA;AAAA,cAAA;;;;;yBAKvB,MAAQ;AAAA,UAARA,WAAQ,KAAA,QAAA,WAAA,CAAA,GAAA,QAAA,IAAA;AAAA,QAAA;;;;;;;"}