UNPKG

@nextcloud/vue

Version:
1 lines 10.1 kB
{"version":3,"file":"NcSelectUsers-DVTI1DIZ.mjs","sources":["../../src/components/NcSelectUsers/NcSelectUsers.vue"],"sourcesContent":["<!--\n\t- SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors\n\t- SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<docs>\n### Nextcloud user picker\n\n#### Examples\n\n```vue\n<template>\n\t<div class=\"grid\">\n\t\t<div v-for=\"{ props } in selectArray\"\n\t\t\tclass=\"container\">\n\t\t\t<NcSelectUsers v-bind=\"props\"\n\t\t\t\tv-model=\"props.value\" />\n\t\t</div>\n\t</div>\n</template>\n\n<script>\nimport svgAccountGroup from '@mdi/svg/svg/account-group.svg?raw'\nimport svgEmail from '@mdi/svg/svg/email.svg?raw'\n\nconst selectArray = [\n\t{\n\t\tprops: {\n\t\t\tinputLabel: 'User select',\n\t\t\toptions: [\n\t\t\t\t{\n\t\t\t\t\tid: '0-john',\n\t\t\t\t\tdisplayName: 'John',\n\t\t\t\t\tisNoUser: false,\n\t\t\t\t\tsubname: 'john@example.org',\n\t\t\t\t\t// Example of how to show the user status within the option\n\t\t\t\t\tuser: '0-john',\n\t\t\t\t\tpreloadedUserStatus: {\n\t\t\t\t\t\tstatus: 'online',\n\t\t\t\t\t\tmessage: 'I am online',\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: '0-emma',\n\t\t\t\t\tdisplayName: 'Emma',\n\t\t\t\t\tisNoUser: false,\n\t\t\t\t\tsubname: 'emma@example.org',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: '0-olivia',\n\t\t\t\t\tdisplayName: 'Olivia',\n\t\t\t\t\tisNoUser: false,\n\t\t\t\t\tsubname: 'olivia@example.org',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: '0-noah',\n\t\t\t\t\tdisplayName: 'Noah',\n\t\t\t\t\tisNoUser: false,\n\t\t\t\t\tsubname: 'noah@example.org',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: '0-oliver',\n\t\t\t\t\tdisplayName: 'Oliver',\n\t\t\t\t\tisNoUser: false,\n\t\t\t\t\tsubname: 'oliver@example.org',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: '1-admin',\n\t\t\t\t\tdisplayName: 'Admin',\n\t\t\t\t\tisNoUser: true,\n\t\t\t\t\ticonSvg: svgAccountGroup,\n\t\t\t\t\ticonName: 'Group icon',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: '2-org@example.org',\n\t\t\t\t\tdisplayName: 'Organization',\n\t\t\t\t\tisNoUser: true,\n\t\t\t\t\tsubname: 'org@example.org',\n\t\t\t\t\ticonSvg: svgEmail,\n\t\t\t\t\ticonName: 'Email icon',\n\t\t\t\t},\n\t\t\t],\n\t\t},\n\t},\n\n\t{\n\t\tprops: {\n\t\t\tinputLabel: 'Multiple user select (stay open on select)',\n\t\t\tkeepOpen: true,\n\t\t\tmultiple: true,\n\t\t\toptions: [\n\t\t\t\t{\n\t\t\t\t\tid: '0-john',\n\t\t\t\t\tdisplayName: 'John',\n\t\t\t\t\tisNoUser: false,\n\t\t\t\t\tsubname: 'john@example.org',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: '0-emma',\n\t\t\t\t\tdisplayName: 'Emma',\n\t\t\t\t\tisNoUser: false,\n\t\t\t\t\tsubname: 'emma@example.org',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: '0-olivia',\n\t\t\t\t\tdisplayName: 'Olivia',\n\t\t\t\t\tisNoUser: false,\n\t\t\t\t\tsubname: 'olivia@example.org',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: '0-noah',\n\t\t\t\t\tdisplayName: 'Noah',\n\t\t\t\t\tisNoUser: false,\n\t\t\t\t\tsubname: 'noah@example.org',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: '0-oliver',\n\t\t\t\t\tdisplayName: 'Oliver',\n\t\t\t\t\tisNoUser: false,\n\t\t\t\t\tsubname: 'oliver@example.org',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: '1-admin',\n\t\t\t\t\tdisplayName: 'Admin',\n\t\t\t\t\tisNoUser: true,\n\t\t\t\t\ticonSvg: svgAccountGroup,\n\t\t\t\t\ticonName: 'Group icon',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: '2-org@example.org',\n\t\t\t\t\tdisplayName: 'Organization',\n\t\t\t\t\tisNoUser: true,\n\t\t\t\t\tsubname: 'org@example.org',\n\t\t\t\t\ticonSvg: svgEmail,\n\t\t\t\t\ticonName: 'Email icon',\n\t\t\t\t},\n\t\t\t],\n\t\t},\n\t},\n]\n\nexport default {\n\tdata() {\n\t\treturn {\n\t\t\tselectArray,\n\t\t}\n\t},\n}\n</script>\n\n<style>\n.grid {\n\tdisplay: grid;\n\tgrid-template-columns: repeat(1, 500px);\n\tgap: 10px;\n}\n\n.container {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px 0;\n}\n</style>\n```\n</docs>\n\n<script setup lang=\"ts\">\nimport { ref, watch } from 'vue'\nimport NcListItemIcon from '../NcListItemIcon/index.js'\nimport NcSelect from '../NcSelect/index.js'\n\nexport interface IUserData {\n\tid: string\n\n\t/**\n\t * Main display name\n\t */\n\tdisplayName: string\n\n\t/**\n\t * The user id.\n\t * Will be used to fetch the user status if not disabled.\n\t */\n\tuser?: string\n\n\t/**\n\t * The secondary displayname (e.g. the email address).\n\t */\n\tsubname?: string\n\n\t/**\n\t * Optional icon to use as the avatar.\n\t * Setting this will disable the automatic avatar loading.\n\t */\n\ticonSvg?: string\n\n\t/**\n\t * Accessible name for the icon.\n\t */\n\ticonName?: string\n\n\t/**\n\t * If this is a guest user.\n\t * Needed as guest users have a different API endpoint for avatar loading.\n\t */\n\tisGuest?: boolean\n\n\t/**\n\t * Set if this is not a regular user.\n\t * This will disable user status and avatar loading.\n\t */\n\tisNoUser?: boolean\n}\n\n/**\n * Currently selected value.\n * The `v-model` directive may be used for two-way data binding.\n *\n * If the `multiple` property is set then an array of users is emitted,\n * otherwise a single user data object will be emitted.\n */\nconst modelValue = defineModel<IUserData | IUserData[]>('modelValue')\n\ndefineProps<{\n\t/**\n\t * `aria-label` for the clear input button.\n\t *\n\t * @default 'Clear selected'\n\t */\n\tariaLabelClearSelected?: string\n\n\t/**\n\t * `aria-label` for the listbox element.\n\t *\n\t * @default 'Options'\n\t */\n\tariaLabelListbox?: string\n\n\t/**\n\t * Allows to customize the `aria-label` for the deselect-option button.\n\t *\n\t * @default (label) => `Deselect ${label}`\n\t */\n\tariaLabelDeselectOption?: (label: string) => string\n\n\t/**\n\t * Disable the component.\n\t */\n\tdisabled?: boolean\n\n\t/**\n\t * Input element id.\n\t *\n\t * @default random generated id\n\t */\n\tinputId?: string\n\n\t/**\n\t * Visible label for the input element\n\t *\n\t * @default 'Select account'\n\t */\n\tinputLabel?: string\n\n\t/**\n\t * Pass true if you are using an external label.\n\t * In this case make sure you set the `for` attribute of your `<label>` to the `inputId` of this component.\n\t */\n\tlabelOutside?: boolean\n\n\t/**\n\t * Keep the dropdown open after selecting an entry.\n\t */\n\tkeepOpen?: boolean\n\n\t/**\n\t * Show a loading icon.\n\t */\n\tloading?: boolean\n\n\t/**\n\t * Allow selection of multiple options\n\t */\n\tmultiple?: boolean\n\n\t/**\n\t * Disable automatic wrapping when selected options overflow the width.\n\t */\n\tnoWrap?: boolean\n\n\t/**\n\t * Array of users or similar object (e.g. groups or guest users).\n\t */\n\toptions: IUserData[]\n\n\t/**\n\t * Placeholder text.\n\t *\n\t * @default ''\n\t */\n\tplaceholder?: string\n\n\t/**\n\t * Enable if a value is required for native form validation.\n\t */\n\trequired?: boolean\n}>()\n\nconst emit = defineEmits<{\n\t/**\n\t * Emitted when the user enters some query.\n\t * This can be used to asynchronously fetch more options.\n\t */\n\tsearch: [string]\n}>()\n\nconst search = ref('')\nwatch(search, () => emit('search', search.value))\n\n// Avatar size so the component has the same size as Nc*Field\nconst clickableArea = Number.parseInt(window.getComputedStyle(document.body).getPropertyValue('--default-clickable-area'))\nconst gridBaseLine = Number.parseInt(window.getComputedStyle(document.body).getPropertyValue('--default-grid-baseline'))\nconst avatarSize = clickableArea - 2 * gridBaseLine\n\n/**\n * Filter function to search users.\n *\n * @param option - The option to check\n * @param option.subname - The second line to check (often the email address)\n * @param label - The label of the option\n * @param search - The current search string\n */\nfunction filterBy(option: { subname?: string }, label: string, search: string) {\n\t// Match the email notation like \"Jane <j.doe@example.com>\" with the email address as matching group\n\tconst EMAIL_NOTATION = /[^<]*<([^>]+)/\n\n\tconst match = search.match(EMAIL_NOTATION)\n\tconst subname = option.subname?.toLocaleLowerCase() ?? ''\n\treturn (match && subname.indexOf(match[1]!.toLocaleLowerCase()) > -1)\n\t\t|| (`${label} ${option.subname}`\n\t\t\t.toLocaleLowerCase()\n\t\t\t.indexOf(search.toLocaleLowerCase()) > -1)\n}\n</script>\n\n<template>\n\t<NcSelect\n\t\tv-model=\"modelValue\"\n\t\tclass=\"nc-select-users\"\n\t\tv-bind=\"$props\"\n\t\t:filter-by\n\t\tlabel=\"displayName\"\n\t\t@search=\"search = $event\">\n\t\t<template #option=\"option\">\n\t\t\t<NcListItemIcon\n\t\t\t\tv-bind=\"option\"\n\t\t\t\t:avatar-size=\"32\"\n\t\t\t\t:name=\"option.displayName\"\n\t\t\t\t:search />\n\t\t</template>\n\t\t<template #selected-option=\"selectedOption\">\n\t\t\t<NcListItemIcon\n\t\t\t\tv-bind=\"selectedOption\"\n\t\t\t\t:avatar-size\n\t\t\t\t:name=\"selectedOption.displayName\"\n\t\t\t\tno-margin\n\t\t\t\t:search />\n\t\t</template>\n\t</NcSelect>\n</template>\n\n<style scoped lang=\"css\">\n.nc-select-users :deep(.vs__selected) {\n\tpadding-inline: 0 5px !important;\n}\n</style>\n"],"names":["_useModel","search","_openBlock","_createBlock","_unref","_mergeProps","$props","_withCtx","_createVNode"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AA6NA,UAAM,aAAaA,SAAoC,SAAC,YAAY;AAuFpE,UAAM,OAAO;AAQb,UAAM,SAAS,IAAI,EAAE;AACrB,UAAM,QAAQ,MAAM,KAAK,UAAU,OAAO,KAAK,CAAC;AAGhD,UAAM,gBAAgB,OAAO,SAAS,OAAO,iBAAiB,SAAS,IAAI,EAAE,iBAAiB,0BAA0B,CAAC;AACzH,UAAM,eAAe,OAAO,SAAS,OAAO,iBAAiB,SAAS,IAAI,EAAE,iBAAiB,yBAAyB,CAAC;AACvH,UAAM,aAAa,gBAAgB,IAAI;AAUvC,aAAS,SAAS,QAA8B,OAAeC,SAAgB;AAE9E,YAAM,iBAAiB;AAEvB,YAAM,QAAQA,QAAO,MAAM,cAAc;AACzC,YAAM,UAAU,OAAO,SAAS,kBAAA,KAAuB;AACvD,aAAQ,SAAS,QAAQ,QAAQ,MAAM,CAAC,EAAG,kBAAA,CAAmB,IAAI,MAC7D,GAAG,KAAK,IAAI,OAAO,OAAO,GAC5B,oBACA,QAAQA,QAAO,kBAAA,CAAmB,IAAI;AAAA,IAC1C;;AAIC,aAAAC,aAAAC,YAsBWC,iBAtBXC,WAsBW;AAAA,oBArBD,WAAA;AAAA,qEAAA,WAAU,QAAA;AAAA,QACnB,OAAM;AAAA,MAAA,GACEC,KAAAA,QAAM;AAAA,QACb,aAAA;AAAA,QACD,OAAM;AAAA,QACL,UAAM,OAAA,CAAA,MAAA,OAAA,CAAA,IAAA,CAAA,WAAE,OAAA,QAAS;AAAA,MAAA;QACP,QAAMC,QAChB,CAIW,WALa;AAAA,UACxBC,YAIWJ,MAAA,cAAA,GAJXC,WAIW,QAHI;AAAA,YACb,eAAa;AAAA,YACb,MAAM,OAAO;AAAA,YACb,QAAA,OAAA;AAAA,UAAA;;QAEQ,mBAAeE,QACzB,CAKW,mBAN8B;AAAA,UACzCC,YAKWJ,MAAA,cAAA,GALXC,WAKW,gBAJY;AAAA,YACrB,eAAA;AAAA,YACA,MAAM,eAAe;AAAA,YACtB,aAAA;AAAA,YACC,QAAA,OAAA;AAAA,UAAA;;;;;;;;"}