@nextcloud/vue 9.12.0 → 9.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/dist/assets/NcAppContent.css +20 -20
- package/dist/assets/NcAppNavigation.css +13 -13
- package/dist/assets/NcAppNavigationSettings.css +6 -6
- package/dist/assets/NcAppSettingsDialog.css +3 -3
- package/dist/assets/NcAppSettingsShortcutsSection.css +1 -1
- package/dist/assets/NcAppSidebar.css +28 -28
- package/dist/assets/NcAssistantButton.css +9 -9
- package/dist/assets/NcAssistantContent.css +3 -3
- package/dist/assets/NcAssistantIcon.css +4 -4
- package/dist/assets/NcAvatar.css +26 -26
- package/dist/assets/NcBlurHash.css +2 -2
- package/dist/assets/NcDateTimePicker.css +234 -234
- package/dist/assets/NcDialog.css +16 -16
- package/dist/assets/NcFilePicker.css +1 -1
- package/dist/assets/NcFormBox.css +11 -11
- package/dist/assets/NcFormBoxButton.css +2 -2
- package/dist/assets/NcFormBoxItem.css +15 -15
- package/dist/assets/NcFormBoxSwitch.css +2 -2
- package/dist/assets/NcFormGroup.css +7 -7
- package/dist/assets/NcHotkey.css +8 -8
- package/dist/assets/NcHotkeyList.css +2 -2
- package/dist/assets/NcIconToggleSwitch.css +4 -4
- package/dist/assets/NcKbd.css +3 -3
- package/dist/assets/NcModal.css +71 -64
- package/dist/assets/NcPopover.css +16 -16
- package/dist/assets/NcRadioGroup.css +2 -2
- package/dist/assets/NcRadioGroupButton.css +14 -14
- package/dist/assets/NcReferenceWidget.css +24 -23
- package/dist/assets/NcRichContenteditable.css +17 -17
- package/dist/assets/NcSelect.css +8 -13
- package/dist/assets/NcUploadPicker.css +7 -7
- package/dist/assets/autolink.css +3 -3
- package/dist/chunks/NcAppContent.mjs +170 -297
- package/dist/chunks/NcAppContent.mjs.map +1 -1
- package/dist/chunks/NcAppContentList.vue_vue_type_script_setup_true_lang.mjs +21 -0
- package/dist/chunks/NcAppContentList.vue_vue_type_script_setup_true_lang.mjs.map +1 -0
- package/dist/chunks/NcAppNavigation.mjs +7 -4
- package/dist/chunks/NcAppNavigation.mjs.map +1 -1
- package/dist/chunks/NcAppNavigationSettings.mjs +6 -6
- package/dist/chunks/NcAppSettingsDialog.mjs +4 -4
- package/dist/chunks/NcAppSettingsShortcutsSection.mjs +1 -1
- package/dist/chunks/NcAppSidebar.mjs +12 -12
- package/dist/chunks/NcAssistantButton.mjs +7 -7
- package/dist/chunks/NcAssistantContent.mjs +3 -3
- package/dist/chunks/NcAssistantIcon.mjs +4 -4
- package/dist/chunks/NcAvatar.mjs +14 -7
- package/dist/chunks/NcAvatar.mjs.map +1 -1
- package/dist/chunks/NcBlurHash.mjs +2 -2
- package/dist/chunks/NcContent.mjs +1 -1
- package/dist/chunks/NcDateTimePicker.mjs +39 -1
- package/dist/chunks/NcDateTimePicker.mjs.map +1 -1
- package/dist/chunks/NcDialog.mjs +1 -1
- package/dist/chunks/NcDialog.mjs.map +1 -1
- package/dist/chunks/NcFilePicker.mjs +1 -1
- package/dist/chunks/NcFormBox.mjs +5 -5
- package/dist/chunks/NcFormBoxButton.mjs +2 -2
- package/dist/chunks/NcFormBoxItem.mjs +8 -8
- package/dist/chunks/NcFormBoxSwitch.mjs +2 -2
- package/dist/chunks/NcFormGroup.mjs +7 -7
- package/dist/chunks/NcHotkey.mjs +4 -4
- package/dist/chunks/NcHotkeyList.mjs +2 -2
- package/dist/chunks/NcIconToggleSwitch.mjs +2 -2
- package/dist/chunks/NcKbd.mjs +2 -2
- package/dist/chunks/NcMentionBubble.vue_vue_type_style_index_0_scoped_3c4a673d_lang.mjs +7 -7
- package/dist/chunks/NcMentionBubble.vue_vue_type_style_index_0_scoped_3c4a673d_lang.mjs.map +1 -1
- package/dist/chunks/NcModal.mjs +11 -12
- package/dist/chunks/NcModal.mjs.map +1 -1
- package/dist/chunks/NcPopover.mjs +2 -2
- package/dist/chunks/NcPopover.mjs.map +1 -1
- package/dist/chunks/NcRadioGroup.mjs +2 -2
- package/dist/chunks/NcRadioGroupButton.mjs +6 -6
- package/dist/chunks/NcReferenceWidget.mjs +2 -2
- package/dist/chunks/NcReferenceWidget.mjs.map +1 -1
- package/dist/chunks/NcRichContenteditable.mjs +10 -10
- package/dist/chunks/NcSelect.mjs.map +1 -1
- package/dist/chunks/NcUploadPicker.mjs +6 -6
- package/dist/chunks/NcUploadPicker.mjs.map +1 -1
- package/dist/chunks/_l10n.mjs +24 -24
- package/dist/chunks/autolink.mjs +3 -3
- package/dist/components/NcAppContent/NcAppContent.vue.d.ts +77 -149
- package/dist/components/NcAppContent/index.d.ts +5 -0
- package/dist/components/NcAppContentList/NcAppContentList.vue.d.ts +28 -27
- package/dist/components/NcAppContentList/index.d.ts +4 -0
- package/dist/components/NcAppContentList/index.mjs +2 -2
- package/dist/components/NcAvatar/NcAvatar.vue.d.ts +17 -0
- package/dist/components/NcCollectionList/NcCollectionList.vue.d.ts +18 -0
- package/dist/components/NcCollectionList/NcCollectionListItem.vue.d.ts +9 -0
- package/dist/components/NcDashboardWidget/NcDashboardWidget.vue.d.ts +18 -0
- package/dist/components/NcDashboardWidgetItem/NcDashboardWidgetItem.vue.d.ts +9 -0
- package/dist/components/NcDateTimePicker/formatValidation.d.ts +10 -0
- package/dist/components/NcListItemIcon/NcListItemIcon.vue.d.ts +9 -0
- package/dist/components/NcModal/NcModal.vue.d.ts +3 -0
- package/dist/components/NcRichText/NcReferencePicker/NcReferencePickerModal.vue.d.ts +8 -0
- package/dist/components/index.d.ts +2 -2
- package/dist/index.mjs +169 -169
- package/dist/utils/getAvatarUrl.d.ts +4 -0
- package/package.json +11 -11
- package/dist/chunks/NcAppContentList.mjs +0 -33
- package/dist/chunks/NcAppContentList.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NcSelect.mjs","sources":["../../src/components/NcSelect/NcSelect.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<docs>\n### Description\n\nGeneral purpose multiselect component.\n\n### Basic 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<NcSelect v-bind=\"props\"\n\t\t\t\tv-model=\"props.value\" />\n\t\t</div>\n\t</div>\n</template>\n\n<script>\nconst selectArray = [\n\t{\n\t\tprops: {\n\t\t\tinputLabel: 'Simple',\n\t\t\toptions: [\n\t\t\t\t'foo',\n\t\t\t\t'bar',\n\t\t\t\t'baz',\n\t\t\t\t'qux',\n\t\t\t\t'quux',\n\t\t\t],\n\t\t},\n\t},\n\n\t{\n\t\tprops: {\n\t\t\tinputLabel: 'With helper text',\n\t\t\thelperText: 'Choose the option that fits best',\n\t\t\toptions: [\n\t\t\t\t'foo',\n\t\t\t\t'bar',\n\t\t\t\t'baz',\n\t\t\t],\n\t\t},\n\t},\n\n\t{\n\t\tprops: {\n\t\t\tinputLabel: 'With error',\n\t\t\thelperText: 'This selection is required',\n\t\t\terror: true,\n\t\t\toptions: [\n\t\t\t\t'foo',\n\t\t\t\t'bar',\n\t\t\t\t'baz',\n\t\t\t],\n\t\t},\n\t},\n\n\t{\n\t\tprops: {\n\t\t\tinputLabel: 'Simple (top placement)',\n\t\t\tplacement: 'top',\n\t\t\toptions: [\n\t\t\t\t'foo',\n\t\t\t\t'bar',\n\t\t\t\t'baz',\n\t\t\t\t'qux',\n\t\t\t\t'quux',\n\t\t\t],\n\t\t},\n\t},\n\n\t{\n\t\tprops: {\n\t\t\tinputLabel: 'Multiple (with placeholder)',\n\t\t\tmultiple: true,\n\t\t\tplaceholder: 'Select multiple options',\n\t\t\toptions: [\n\t\t\t\t'foo',\n\t\t\t\t'bar',\n\t\t\t\t'baz',\n\t\t\t\t'qux',\n\t\t\t\t'quux',\n\t\t\t],\n\t\t},\n\t},\n\n\t{\n\t\tprops: {\n\t\t\tinputLabel: 'Multiple (objects, pre-selected, 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: 'foo',\n\t\t\t\t\tlabel: 'Foo',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: 'bar',\n\t\t\t\t\tlabel: 'Bar',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: 'baz',\n\t\t\t\t\tlabel: 'Baz',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: 'qux',\n\t\t\t\t\tlabel: 'Qux',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: 'quux',\n\t\t\t\t\tlabel: 'Quux',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: 'corge',\n\t\t\t\t\tlabel: 'Corge',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: 'grault',\n\t\t\t\t\tlabel: 'Grault',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: 'garply',\n\t\t\t\t\tlabel: 'Garply',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: 'waldo',\n\t\t\t\t\tlabel: 'Waldo',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: 'fred',\n\t\t\t\t\tlabel: 'Fred',\n\t\t\t\t},\n\t\t\t],\n\t\t\tvalue: [\n\t\t\t\t{\n\t\t\t\t\tid: 'foo',\n\t\t\t\t\tlabel: 'Foo',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: 'bar',\n\t\t\t\t\tlabel: 'Bar',\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(2, 1fr);\n\tgap: 10px;\n}\n\n.container {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px 0;\n}\n</style>\n```\n\n### Pre-selected and clearable\n\n```vue\n<template>\n\t<div class=\"grid\">\n\t\t<div class=\"container\">\n\t\t\t<NcSelect v-model=\"singleValue\"\n\t\t\t\tinput-label=\"Clearable single\"\n\t\t\t\t:options=\"options\"\n\t\t\t\tclearable />\n\t\t</div>\n\t\t<div class=\"container\">\n\t\t\t<NcSelect v-model=\"singlePlaceholder\"\n\t\t\t\tinput-label=\"With placeholder\"\n\t\t\t\tplaceholder=\"Search for something...\"\n\t\t\t\t:options=\"options\" />\n\t\t</div>\n\t</div>\n</template>\n\n<script>\nexport default {\n\tdata() {\n\t\treturn {\n\t\t\toptions: ['foo', 'bar', 'baz', 'qux', 'quux'],\n\t\t\tsingleValue: 'bar',\n\t\t\tsinglePlaceholder: null,\n\t\t}\n\t},\n}\n</script>\n\n<style>\n.grid {\n\tdisplay: grid;\n\tgrid-template-columns: repeat(2, 1fr);\n\tgap: 10px;\n}\n\n.container {\n\tdisplay: flex;\n\tflex-direction: column;\n}\n</style>\n```\n\n### Disabled state\n\n```vue\n<template>\n\t<div class=\"grid\">\n\t\t<div class=\"container\">\n\t\t\t<NcSelect v-model=\"singleValue\"\n\t\t\t\tinput-label=\"Disabled single\"\n\t\t\t\t:options=\"options\"\n\t\t\t\tdisabled />\n\t\t</div>\n\t\t<div class=\"container\">\n\t\t\t<NcSelect v-model=\"multiValue\"\n\t\t\t\tinput-label=\"Disabled multi\"\n\t\t\t\t:options=\"options\"\n\t\t\t\tmultiple\n\t\t\t\tdisabled />\n\t\t</div>\n\t</div>\n</template>\n\n<script>\nexport default {\n\tdata() {\n\t\treturn {\n\t\t\toptions: ['foo', 'bar', 'baz'],\n\t\t\tsingleValue: 'foo',\n\t\t\tmultiValue: ['foo', 'bar'],\n\t\t}\n\t},\n}\n</script>\n\n<style>\n.grid {\n\tdisplay: grid;\n\tgrid-template-columns: repeat(2, 1fr);\n\tgap: 10px;\n}\n\n.container {\n\tdisplay: flex;\n\tflex-direction: column;\n}\n</style>\n```\n\n### Label outside\n\n```vue\n<template>\n\t<div class=\"grid\">\n\t\t<div class=\"container\">\n\t\t\t<label for=\"ext-single\">External label (single)</label>\n\t\t\t<NcSelect v-model=\"singleValue\"\n\t\t\t\tinput-id=\"ext-single\"\n\t\t\t\tlabel-outside\n\t\t\t\tplaceholder=\"Pick an option\"\n\t\t\t\t:options=\"options\" />\n\t\t</div>\n\t\t<div class=\"container\">\n\t\t\t<label for=\"ext-multi\">External label (multi)</label>\n\t\t\t<NcSelect v-model=\"multiValue\"\n\t\t\t\tinput-id=\"ext-multi\"\n\t\t\t\tlabel-outside\n\t\t\t\t:options=\"options\"\n\t\t\t\tmultiple />\n\t\t</div>\n\t</div>\n</template>\n\n<script>\nexport default {\n\tdata() {\n\t\treturn {\n\t\t\toptions: ['foo', 'bar', 'baz', 'qux', 'quux'],\n\t\t\tsingleValue: null,\n\t\t\tmultiValue: [],\n\t\t}\n\t},\n}\n</script>\n\n<style>\n.grid {\n\tdisplay: grid;\n\tgrid-template-columns: repeat(2, 1fr);\n\tgap: 10px;\n}\n\n.container {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n</style>\n```\n\n### Native form validation example\n\n```vue\n<template>\n\t<div class=\"container\">\n\t\t<form class=\"container__form\" @submit.prevent>\n\t\t\t<NcSelect class=\"container__select\"\n\t\t\t\tinput-label=\"Require a selection\"\n\t\t\t\t:options=\"options\"\n\t\t\t\tv-model=\"singleValue\"\n\t\t\t\trequired />\n\t\t\t<NcButton type=\"submit\">Submit</NcButton>\n\t\t</form>\n\n\t\t<form class=\"container__form\" @submit.prevent>\n\t\t\t<NcSelect class=\"container__select\"\n\t\t\t\tinput-label=\"Require at least one selection\"\n\t\t\t\t:options=\"options\"\n\t\t\t\tv-model=\"multiValue\"\n\t\t\t\tmultiple\n\t\t\t\trequired />\n\t\t\t<NcButton type=\"submit\">Submit</NcButton>\n\t\t</form>\n\t</div>\n</template>\n\n<script>\nexport default {\n\tdata() {\n\t\treturn {\n\t\t\toptions: ['foo', 'bar', 'baz', 'qux', 'quux'],\n\t\t\tsingleValue: null,\n\t\t\tmultiValue: [],\n\t\t}\n\t},\n}\n</script>\n\n<style>\n.container {\n\tdisplay: flex;\n\tgap: 0 12px;\n}\n\n.container__form {\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: flex-end;\n\twidth: 100%;\n\tgap: 8px 0;\n}\n\n.container__select {\n\twidth: 100%;\n}\n</style>\n```\n\n### No wrap example\n\nThe `noWrap` prop is set to `true` and the `max-width` of the multiselect\nparent container is limited to `350px`\n\n```vue\n<template>\n\t<div class=\"grid\">\n\t\t<div class=\"container\">\n\t\t\t<NcSelect :no-wrap=\"false\"\n\t\t\t\tv-bind=\"data1.props\"\n\t\t\t\tv-model=\"data1.props.value\" />\n\t\t</div>\n\t\t<div class=\"container\">\n\t\t\t<NcSelect :no-wrap=\"true\"\n\t\t\t\tv-bind=\"data2.props\"\n\t\t\t\tv-model=\"data2.props.value\" />\n\t\t</div>\n\t</div>\n</template>\n\n<script>\nconst data1 = {\n\tprops: {\n\t\tinputLabel: 'Wrapped (Default)',\n\t\tmultiple: true,\n\t\tkeepOpen: true,\n\t\toptions: [\n\t\t\t'foo',\n\t\t\t'bar',\n\t\t\t'baz',\n\t\t\t'qux',\n\t\t\t'quux',\n\t\t\t'corge',\n\t\t\t'grault',\n\t\t\t'garply',\n\t\t\t'waldo',\n\t\t\t'fred',\n\t\t],\n\t\tvalue: [\n\t\t\t'foo',\n\t\t\t'bar',\n\t\t\t'baz',\n\t\t\t'qux',\n\t\t\t'quux',\n\t\t\t'corge',\n\t\t\t'grault',\n\t\t\t'garply',\n\t\t\t'waldo',\n\t\t\t'fred',\n\t\t],\n\t},\n}\n\nconst data2 = {\n\tprops: {\n\t\tinputLabel: 'Not wrapped',\n\t\tkeepOpen: true,\n\t\tmultiple: true,\n\t\toptions: [\n\t\t\t'foo',\n\t\t\t'bar',\n\t\t\t'baz',\n\t\t\t'qux',\n\t\t\t'quux',\n\t\t\t'corge',\n\t\t\t'grault',\n\t\t\t'garply',\n\t\t\t'waldo',\n\t\t\t'fred',\n\t\t],\n\t\tvalue: [\n\t\t\t'foo',\n\t\t\t'bar',\n\t\t\t'baz',\n\t\t\t'qux',\n\t\t\t'quux',\n\t\t\t'corge',\n\t\t\t'grault',\n\t\t\t'garply',\n\t\t\t'waldo',\n\t\t\t'fred',\n\t\t],\n\t},\n}\n\nexport default {\n\tdata() {\n\t\treturn {\n\t\t\tdata1,\n\t\t\tdata2,\n\t\t}\n\t},\n}\n</script>\n\n<style>\n.grid {\n\tdisplay: grid;\n\tgrid-template-columns: repeat(1, 1fr);\n\tgap: 10px;\n}\n\n.container {\n\tmax-width: 350px;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px 0;\n}\n</style>\n```\n</docs>\n\n<template>\n\t<VueSelect\n\t\tclass=\"select nc-select\"\n\t\t:class=\"{\n\t\t\t'select--legacy': isLegacy,\n\t\t\t'select--no-wrap': noWrap,\n\t\t}\"\n\t\tv-bind=\"propsToForward\"\n\t\t@search=\"search = $event\"\n\t\t@update:modelValue=\"$emit('update:modelValue', $event)\">\n\t\t<template v-if=\"multiple && !labelOutside && inputLabel\" #header>\n\t\t\t<label\n\t\t\t\t:for=\"inputId\"\n\t\t\t\tclass=\"select__label\">\n\t\t\t\t{{ inputLabel }}\n\t\t\t</label>\n\t\t</template>\n\t\t<template #search=\"{ attributes, events }\">\n\t\t\t<!--\n\t\t\t\tvue-select's `attributes`/`events` are its search-slot contract, not\n\t\t\t\tHTML pass-through, so we forward only the combobox a11y attributes and\n\t\t\t\tevents one by one. This skips `attributes.ref` (a vue-select template\n\t\t\t\tref) and lets our own `modelValue`, `placeholder`, `label` and\n\t\t\t\t`disabled` win over their vue-select equivalents.\n\t\t\t\tNo placeholder when: multi mode (select__label is the placeholder) or a\n\t\t\t\tvalue is selected (the vs__selected overlay shows it instead).\n\t\t\t-->\n\t\t\t<NcTextField\n\t\t\t\t:id=\"attributes.id\"\n\t\t\t\tclass=\"vs__search\"\n\t\t\t\t:class=\"[inputClass]\"\n\t\t\t\t:type=\"attributes.type\"\n\t\t\t\t:modelValue=\"attributes.value\"\n\t\t\t\t:placeholder=\"multiple || modelValue ? '' : (placeholder || '')\"\n\t\t\t\t:label=\"!labelOutside && !multiple && inputLabel ? inputLabel : ''\"\n\t\t\t\t:labelOutside=\"labelOutside || multiple\"\n\t\t\t\t:disabled=\"disabled\"\n\t\t\t\t:required=\"inputRequired\"\n\t\t\t\t:role=\"attributes.role\"\n\t\t\t\t:tabindex=\"attributes.tabindex\"\n\t\t\t\t:readonly=\"attributes.readonly\"\n\t\t\t\t:autocomplete=\"attributes.autocomplete\"\n\t\t\t\t:aria-label=\"attributes['aria-label']\"\n\t\t\t\t:aria-describedby=\"[attributes['aria-describedby'], helperText ? `${inputId}-helper-text` : null].filter(Boolean).join(' ') || undefined\"\n\t\t\t\t:aria-autocomplete=\"attributes['aria-autocomplete']\"\n\t\t\t\t:aria-controls=\"attributes['aria-controls']\"\n\t\t\t\t:aria-owns=\"attributes['aria-owns']\"\n\t\t\t\t:aria-expanded=\"attributes['aria-expanded']\"\n\t\t\t\t:aria-activedescendant=\"attributes['aria-activedescendant']\"\n\t\t\t\t@keydown=\"events.keydown\"\n\t\t\t\t@keypress=\"events.keypress\"\n\t\t\t\t@focus=\"events.focus\"\n\t\t\t\t@blur=\"events.blur\"\n\t\t\t\t@compositionstart=\"events.compositionstart\"\n\t\t\t\t@compositionend=\"events.compositionend\"\n\t\t\t\t@update:modelValue=\"events.input({ target: { value: $event } })\" />\n\t\t</template>\n\t\t<template #open-indicator=\"{ attributes }\">\n\t\t\t<ChevronDown\n\t\t\t\tv-bind=\"attributes\"\n\t\t\t\tfillColor=\"var(--vs-controls-color)\"\n\t\t\t\t:style=\"{\n\t\t\t\t\tcursor: !disabled ? 'pointer' : null,\n\t\t\t\t}\"\n\t\t\t\t:size=\"20\" />\n\t\t</template>\n\t\t<template #option=\"option\">\n\t\t\t<!-- @slot Customize how a option is rendered. -->\n\t\t\t<slot name=\"option\" v-bind=\"option\">\n\t\t\t\t<NcEllipsisedOption\n\t\t\t\t\t:name=\"String(option[localLabel])\"\n\t\t\t\t\t:search=\"search\" />\n\t\t\t</slot>\n\t\t</template>\n\t\t<template #selected-option=\"selectedOption\">\n\t\t\t<!-- @slot Customize how a selected option is rendered -->\n\t\t\t<slot name=\"selected-option\" v-bind=\"selectedOption\">\n\t\t\t\t<NcEllipsisedOption\n\t\t\t\t\t:name=\"String(selectedOption[localLabel])\"\n\t\t\t\t\t:search=\"search\" />\n\t\t\t</slot>\n\t\t</template>\n\t\t<template #spinner=\"spinner\">\n\t\t\t<NcLoadingIcon v-if=\"spinner.loading\" />\n\t\t</template>\n\t\t<template #no-options>\n\t\t\t{{ t('No results') }}\n\t\t</template>\n\t\t<!-- Helper text beneath the control, plus any consumer-provided footer slot -->\n\t\t<template v-if=\"helperText || $slots.footer\" #footer=\"data\">\n\t\t\t<p\n\t\t\t\tv-if=\"helperText\"\n\t\t\t\t:id=\"`${inputId}-helper-text`\"\n\t\t\t\tclass=\"select__helper-text\"\n\t\t\t\t:class=\"{\n\t\t\t\t\t'select__helper-text--error': error,\n\t\t\t\t\t'select__helper-text--success': success,\n\t\t\t\t}\">\n\t\t\t\t<NcIconSvgWrapper\n\t\t\t\t\tv-if=\"success\"\n\t\t\t\t\tclass=\"select__helper-text-icon\"\n\t\t\t\t\t:path=\"mdiCheck\"\n\t\t\t\t\tinline />\n\t\t\t\t<NcIconSvgWrapper\n\t\t\t\t\tv-else-if=\"error\"\n\t\t\t\t\tclass=\"select__helper-text-icon\"\n\t\t\t\t\t:path=\"mdiAlertCircleOutline\"\n\t\t\t\t\tinline />\n\t\t\t\t{{ helperText }}\n\t\t\t</p>\n\t\t\t<slot name=\"footer\" v-bind=\"data\" />\n\t\t</template>\n\t\t<template v-for=\"name in forwardedSlots()\" :key=\"name\" #[name]=\"data\">\n\t\t\t<!-- @slot Any combination of slots from https://vue-select.org/api/slots.html -->\n\t\t\t<slot :name=\"name\" v-bind=\"data\" />\n\t\t</template>\n\t</VueSelect>\n</template>\n\n<script>\nimport {\n\tautoUpdate,\n\tcomputePosition,\n\tflip,\n\tlimitShift,\n\toffset,\n\tshift,\n} from '@floating-ui/dom'\nimport { mdiAlertCircleOutline, mdiCheck } from '@mdi/js'\nimport { VueSelect } from '@nextcloud/vue-select'\nimport { h, warn } from 'vue'\nimport ChevronDown from 'vue-material-design-icons/ChevronDown.vue'\nimport Close from 'vue-material-design-icons/Close.vue'\nimport NcEllipsisedOption from '../NcEllipsisedOption/NcEllipsisedOption.vue'\nimport NcIconSvgWrapper from '../NcIconSvgWrapper/NcIconSvgWrapper.vue'\nimport NcLoadingIcon from '../NcLoadingIcon/NcLoadingIcon.vue'\nimport NcTextField from '../NcTextField/NcTextField.vue'\nimport { t } from '../../l10n.ts'\nimport { createElementId } from '../../utils/createElementId.ts'\nimport { isLegacy } from '../../utils/legacy.ts'\n\nexport default {\n\tname: 'NcSelect',\n\n\tcomponents: {\n\t\tChevronDown,\n\t\tNcEllipsisedOption,\n\t\tNcIconSvgWrapper,\n\t\tNcLoadingIcon,\n\t\tNcTextField,\n\t\tVueSelect,\n\t},\n\n\tprops: {\n\t\t// Add VueSelect props to $props\n\t\t...VueSelect.props,\n\t\t...VueSelect.mixins.reduce((allProps, mixin) => ({ ...allProps, ...mixin.props }), {}),\n\n\t\t/**\n\t\t * `aria-label` for the clear input button\n\t\t */\n\t\tariaLabelClearSelected: {\n\t\t\ttype: String,\n\t\t\tdefault: t('Clear selected'),\n\t\t},\n\n\t\t/**\n\t\t * `aria-label` for the search input\n\t\t *\n\t\t * A descriptive `inputLabel` is preferred as this is not visible.\n\t\t */\n\t\tariaLabelCombobox: {\n\t\t\ttype: String,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * `aria-label` for the listbox element\n\t\t */\n\t\tariaLabelListbox: {\n\t\t\ttype: String,\n\t\t\tdefault: t('Options'),\n\t\t},\n\n\t\t/**\n\t\t * Allows to customize the `aria-label` for the deselect-option button\n\t\t * The default is \"Deselect \" + optionLabel\n\t\t *\n\t\t * @type {(optionLabel: string) => string}\n\t\t */\n\t\tariaLabelDeselectOption: {\n\t\t\ttype: Function,\n\t\t\tdefault: (optionLabel) => t('Deselect {option}', { option: optionLabel }),\n\t\t},\n\n\t\t/**\n\t\t * Append the dropdown element to the end of the body\n\t\t * and size/position it dynamically.\n\t\t *\n\t\t * @see https://vue-select.org/api/props.html#appendtobody\n\t\t */\n\t\tappendToBody: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * When `appendToBody` is true, this function is responsible for\n\t\t * positioning the drop down list.\n\t\t *\n\t\t * If a function is returned from `calculatePosition`, it will\n\t\t * be called when the drop down list is removed from the DOM.\n\t\t * This allows for any garbage collection you may need to do.\n\t\t *\n\t\t * @see https://vue-select.org/api/props.html#calculateposition\n\t\t */\n\t\tcalculatePosition: {\n\t\t\ttype: Function,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Keep the dropdown open after selecting an option.\n\t\t *\n\t\t * @default false\n\t\t * @since 8.25.0\n\t\t */\n\t\tkeepOpen: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Replace default vue-select components\n\t\t *\n\t\t * @see https://vue-select.org/api/props.html#components\n\t\t */\n\t\tcomponents: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({\n\t\t\t\tDeselect: {\n\t\t\t\t\trender: () => h(Close, {\n\t\t\t\t\t\tsize: 20,\n\t\t\t\t\t\tfillColor: 'var(--vs-controls-color)',\n\t\t\t\t\t\tstyle: [\n\t\t\t\t\t\t\t{ cursor: 'pointer' },\n\t\t\t\t\t\t],\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t}),\n\t\t},\n\n\t\t/**\n\t\t * Sets the maximum number of options to display in the dropdown list\n\t\t */\n\t\tlimit: {\n\t\t\ttype: Number,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Disable the component\n\t\t *\n\t\t * @see https://vue-select.org/api/props.html#disabled\n\t\t */\n\t\tdisabled: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Determines whether the dropdown should be open.\n\t\t * Receives the component instance as the only argument.\n\t\t *\n\t\t * @see https://vue-select.org/api/props.html#dropdownshouldopen\n\t\t */\n\t\tdropdownShouldOpen: {\n\t\t\ttype: Function,\n\t\t\tdefault: ({ noDrop, open }) => {\n\t\t\t\treturn noDrop ? false : open\n\t\t\t},\n\t\t},\n\n\t\t/**\n\t\t * Callback to determine if the provided option should\n\t\t * match the current search text. Used to determine\n\t\t * if the option should be displayed.\n\t\t *\n\t\t * Defaults to the internal vue-select function documented at the link\n\t\t * below\n\t\t *\n\t\t * @see https://vue-select.org/api/props.html#filterby\n\t\t */\n\t\tfilterBy: {\n\t\t\ttype: Function,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Class for the `input`\n\t\t *\n\t\t * Necessary for use in NcActionInput\n\t\t */\n\t\tinputClass: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Input element id\n\t\t */\n\t\tinputId: {\n\t\t\ttype: String,\n\t\t\tdefault: () => createElementId(),\n\t\t},\n\n\t\t/**\n\t\t * Visible label for the input element\n\t\t */\n\t\tinputLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Additional helper text shown beneath the select.\n\t\t */\n\t\thelperText: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Toggle the error state, styling the helper text as an error.\n\t\t */\n\t\terror: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Toggle the success state, styling the helper text as a success.\n\t\t */\n\t\tsuccess: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Pass true if you are using an external label\n\t\t */\n\t\tlabelOutside: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Display a visible border around dropdown options\n\t\t * which have keyboard focus\n\t\t */\n\t\tkeyboardFocusBorder: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Key of the displayed label for object options\n\t\t *\n\t\t * Defaults to the internal vue-select string documented at the link\n\t\t * below\n\t\t *\n\t\t * @see https://vue-select.org/api/props.html#label\n\t\t */\n\t\tlabel: {\n\t\t\ttype: String,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Show the loading icon\n\t\t *\n\t\t * @see https://vue-select.org/api/props.html#loading\n\t\t */\n\t\tloading: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Allow selection of multiple options\n\t\t *\n\t\t * @see https://vue-select.org/api/props.html#multiple\n\t\t */\n\t\tmultiple: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Disable automatic wrapping when selected options overflow the width\n\t\t */\n\t\tnoWrap: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Array of options\n\t\t *\n\t\t * @type {Array<string | number | Record<string | number, any>>}\n\t\t *\n\t\t * @see https://vue-select.org/api/props.html#options\n\t\t */\n\t\toptions: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/**\n\t\t * Placeholder text\n\t\t *\n\t\t * @see https://vue-select.org/api/props.html#placeholder\n\t\t */\n\t\tplaceholder: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Customized component's response to keydown events while the search input has focus\n\t\t *\n\t\t * @see https://vue-select.org/guide/keydown.html#mapkeydown\n\t\t */\n\t\tmapKeydown: {\n\t\t\ttype: Function,\n\t\t\t/**\n\t\t\t * Patched Vue-Select keydown events handlers map to stop Escape propagation in open select\n\t\t\t *\n\t\t\t * @param {Record<number, (event: KeyboardEvent) => void>} map - Mapped keyCode to handlers { <keyCode>:<callback> }\n\t\t\t * @param {import('vue').ComponentPublicInstance} vm - VueSelect instance\n\t\t\t * @return {Record<number, (event: KeyboardEvent) => void>} patched keydown event handlers\n\t\t\t */\n\t\t\tdefault(map, vm) {\n\t\t\t\treturn {\n\t\t\t\t\t...map,\n\t\t\t\t\t/**\n\t\t\t\t\t * Patched Escape handler to stop propagation from open select\n\t\t\t\t\t *\n\t\t\t\t\t * @param {KeyboardEvent} event - default keydown event handler\n\t\t\t\t\t */\n\t\t\t\t\t27: (event) => {\n\t\t\t\t\t\tif (vm.open) {\n\t\t\t\t\t\t\tevent.stopPropagation()\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Default VueSelect's handler\n\t\t\t\t\t\tmap[27](event)\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\n\t\t/**\n\t\t * A unique identifier used to generate IDs and DOM attributes. Must be unique for every instance of the component.\n\t\t *\n\t\t * @see https://vue-select.org/api/props.html#uid\n\t\t */\n\t\tuid: {\n\t\t\ttype: String,\n\t\t\tdefault: () => createElementId(),\n\t\t},\n\n\t\t/**\n\t\t * When `appendToBody` is true, this sets the placement of the dropdown\n\t\t *\n\t\t * @type {'bottom' | 'top'}\n\t\t */\n\t\tplacement: {\n\t\t\ttype: String,\n\t\t\tdefault: 'bottom',\n\t\t},\n\n\t\t/**\n\t\t * If false, the focused dropdown option will not be reset when filtered\n\t\t * options change\n\t\t */\n\t\tresetFocusOnOptionsChange: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Currently selected value\n\t\t *\n\t\t * The `v-model` directive may be used for two-way data binding\n\t\t *\n\t\t * @type {string | number | Record<string | number, any> | Array<any>}\n\t\t *\n\t\t * @see https://vue-select.org/api/props.html#value\n\t\t */\n\t\tmodelValue: {\n\t\t\ttype: [String, Number, Object, Array],\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Enable if a value is required for native form validation\n\t\t */\n\t\trequired: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Any available prop\n\t\t *\n\t\t * @see https://vue-select.org/api/props.html\n\t\t */\n\t\t// Not an actual prop but needed to show in vue-styleguidist docs\n\t\t// eslint-disable-next-line\n\t\t' ': {},\n\t},\n\n\temits: [\n\t\t/**\n\t\t * All events from https://vue-select.org/api/events.html\n\t\t */\n\t\t// Not an actual event but needed to show in vue-styleguidist docs\n\t\t' ',\n\t\t'update:modelValue',\n\t],\n\n\tsetup() {\n\t\tconst clickableArea = Number.parseInt(window.getComputedStyle(document.body).getPropertyValue('--default-clickable-area'))\n\t\tconst gridBaseLine = Number.parseInt(window.getComputedStyle(document.body).getPropertyValue('--default-grid-baseline'))\n\t\tconst avatarSize = clickableArea - 2 * gridBaseLine\n\n\t\treturn {\n\t\t\tavatarSize,\n\t\t\tisLegacy,\n\t\t\tmdiAlertCircleOutline,\n\t\t\tmdiCheck,\n\t\t}\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tsearch: '',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tinputRequired() {\n\t\t\tif (!this.required) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\t// The <input> itself does not have any value so we set the `required` attribute conditionally\n\t\t\treturn this.modelValue === null || (Array.isArray(this.modelValue) && this.modelValue.length === 0)\n\t\t},\n\n\t\tlocalCalculatePosition() {\n\t\t\tif (this.calculatePosition !== null) {\n\t\t\t\treturn this.calculatePosition\n\t\t\t}\n\n\t\t\treturn (dropdownMenu, component, { width }) => {\n\t\t\t\tdropdownMenu.style.width = width\n\n\t\t\t\tconst addClass = {\n\t\t\t\t\tname: 'addClass',\n\t\t\t\t\tfn(/* middlewareArgs */) {\n\t\t\t\t\t\t// `nc-select__dropdown` scopes our menu styles: the menu is\n\t\t\t\t\t\t// teleported to <body>, so it cannot be reached by the\n\t\t\t\t\t\t// `.nc-select` root scope and would otherwise style every\n\t\t\t\t\t\t// vue-select dropdown on the page (cross-version conflicts).\n\t\t\t\t\t\tdropdownMenu.classList.add('vs__dropdown-menu--floating', 'nc-select__dropdown')\n\t\t\t\t\t\treturn {}\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\tconst togglePlacementClass = {\n\t\t\t\t\tname: 'togglePlacementClass',\n\t\t\t\t\tfn({ placement }) {\n\t\t\t\t\t\tcomponent.$el.classList.toggle(\n\t\t\t\t\t\t\t'select--drop-up',\n\t\t\t\t\t\t\tplacement === 'top',\n\t\t\t\t\t\t)\n\t\t\t\t\t\tdropdownMenu.classList.toggle(\n\t\t\t\t\t\t\t'vs__dropdown-menu--floating-placement-top',\n\t\t\t\t\t\t\tplacement === 'top',\n\t\t\t\t\t\t)\n\t\t\t\t\t\treturn {}\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\tconst updatePosition = () => {\n\t\t\t\t\tcomputePosition(component.$refs.toggle, dropdownMenu, {\n\t\t\t\t\t\tplacement: this.placement,\n\t\t\t\t\t\tmiddleware: [\n\t\t\t\t\t\t\t// Flip first so the placement-dependent middleware below see the final placement\n\t\t\t\t\t\t\tflip(),\n\t\t\t\t\t\t\taddClass,\n\t\t\t\t\t\t\ttogglePlacementClass,\n\t\t\t\t\t\t\t// On top placement, leave a gap for the floating label overhang\n\t\t\t\t\t\t\t// (about half the floated label line-height) instead of connecting seamlessly\n\t\t\t\t\t\t\toffset(({ placement }) => (placement.startsWith('top') ? 10 : -1)),\n\t\t\t\t\t\t\tshift({ limiter: limitShift() }),\n\t\t\t\t\t\t],\n\t\t\t\t\t}).then(({ x, y }) => {\n\t\t\t\t\t\tObject.assign(dropdownMenu.style, {\n\t\t\t\t\t\t\tleft: `${x}px`,\n\t\t\t\t\t\t\ttop: `${y}px`,\n\t\t\t\t\t\t\twidth: `${component.$refs.toggle.getBoundingClientRect().width}px`,\n\t\t\t\t\t\t})\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\tconst cleanup = autoUpdate(\n\t\t\t\t\tcomponent.$refs.toggle,\n\t\t\t\t\tdropdownMenu,\n\t\t\t\t\tupdatePosition,\n\t\t\t\t)\n\n\t\t\t\treturn cleanup\n\t\t\t}\n\t\t},\n\n\t\tlocalFilterBy() {\n\t\t\treturn this.filterBy ?? VueSelect.props.filterBy.default\n\t\t},\n\n\t\tlocalLabel() {\n\t\t\treturn this.label ?? VueSelect.props.label.default\n\t\t},\n\n\t\tpropsToForward() {\n\t\t\tconst vueSelectKeys = [\n\t\t\t\t...Object.keys(VueSelect.props),\n\t\t\t\t...VueSelect.mixins.flatMap((mixin) => Object.keys(mixin.props ?? {})),\n\t\t\t]\n\t\t\tconst initialPropsToForward = Object.fromEntries(Object.entries(this.$props)\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unused-vars\n\t\t\t\t.filter(([key, _value]) => vueSelectKeys.includes(key)))\n\t\t\tconst propsToForward = {\n\t\t\t\t...initialPropsToForward,\n\t\t\t\t// Custom overrides of vue-select props\n\t\t\t\tcalculatePosition: this.localCalculatePosition,\n\t\t\t\tcloseOnSelect: !this.keepOpen,\n\t\t\t\tfilterBy: this.localFilterBy,\n\t\t\t\tlabel: this.localLabel,\n\t\t\t}\n\t\t\treturn propsToForward\n\t\t},\n\t},\n\n\tmounted() {\n\t\tif (!this.labelOutside && !this.inputLabel && !this.ariaLabelCombobox) {\n\t\t\twarn('[NcSelect] An `inputLabel` or `ariaLabelCombobox` should be set. If an external label is used, `labelOutside` should be set to `true`.')\n\t\t}\n\t\tif (this.inputLabel && this.ariaLabelCombobox) {\n\t\t\twarn('[NcSelect] Only one of `inputLabel` or `ariaLabelCombobox` should to be set.')\n\t\t}\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\t/**\n\t\t * Consumer-provided slots forwarded to vue-select, excluding `footer`\n\t\t * which we render ourselves to host the helper text.\n\t\t *\n\t\t * `$slots` is not reactive, so this is a method (re-evaluated on every\n\t\t * render) rather than a computed, to keep the forwarded slot list fresh.\n\t\t *\n\t\t * @return {string[]}\n\t\t */\n\t\tforwardedSlots() {\n\t\t\treturn Object.keys(this.$slots).filter((name) => name !== 'footer')\n\t\t},\n\t},\n}\n</script>\n\n<style lang=\"scss\">\n@use '../../assets/input-border.scss' as border;\n\n// Helper text beneath the control, matching NcInputField's helper text.\n.nc-select.v-select.select .select__helper-text {\n\tdisplay: flex;\n\talign-items: center;\n\tmargin: 0;\n\tpadding-block: 4px;\n\tpadding-inline: var(--border-radius-element);\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: var(--default-font-size);\n\toverflow-wrap: anywhere;\n\n\t&--error {\n\t\tcolor: var(--color-text-error);\n\t}\n\n\t&--success {\n\t\tcolor: var(--color-text-success);\n\t}\n\n\t.select__helper-text-icon {\n\t\tmargin-inline-end: 8px;\n\t}\n}\n\n.nc-select.v-select.select {\n\t/* Custom vue-select CSS variables scoped to NcSelect */\n\t/* Search Input */\n\t--vs-search-input-color: var(--color-main-text);\n\t--vs-search-input-bg: var(--color-main-background);\n\t--vs-search-input-placeholder-color: var(--color-text-maxcontrast);\n\n\t/* Font */\n\t--vs-font-size: var(--default-font-size);\n\t--vs-line-height: var(--default-line-height);\n\n\t/* Disabled State */\n\t--vs-state-disabled-bg: var(--color-background-hover);\n\t--vs-state-disabled-color: var(--color-text-maxcontrast);\n\t--vs-state-disabled-controls-color: var(--color-text-maxcontrast);\n\t--vs-state-disabled-cursor: not-allowed;\n\t--vs-disabled-bg: var(--color-background-hover);\n\t--vs-disabled-color: var(--color-text-maxcontrast);\n\t--vs-disabled-cursor: not-allowed;\n\n\t/* Borders */\n\t--vs-border-color: var(--color-border-maxcontrast);\n\t--vs-border-width: var(--border-width-input, 2px) !important;\n\t--vs-border-style: solid;\n\t--vs-border-radius: var(--border-radius-element);\n\n\t/* Component Controls: Clear, Open Indicator */\n\t--vs-controls-color: var(--color-main-text);\n\n\t/* Selected */\n\t--vs-selected-bg: var(--color-background-hover);\n\t--vs-selected-color: var(--color-main-text);\n\t--vs-selected-border-color: var(--vs-border-color);\n\t--vs-selected-border-style: var(--vs-border-style);\n\t--vs-selected-border-width: var(--vs-border-width);\n\n\t/* Dropdown */\n\t--vs-dropdown-bg: var(--color-main-background);\n\t--vs-dropdown-color: var(--color-main-text);\n\t--vs-dropdown-z-index: 9999;\n\t--vs-dropdown-box-shadow: 0px 2px 2px 0px var(--color-box-shadow);\n\n\t/* Options */\n\t--vs-dropdown-option-padding: 8px 20px;\n\n\t/* Active State */\n\t--vs-dropdown-option--active-bg: var(--color-background-hover);\n\t--vs-dropdown-option--active-color: var(--color-main-text);\n\n\t/* Keyboard Focus State */\n\t--vs-dropdown-option--kb-focus-box-shadow: inset 0px 0px 0px 2px var(--vs-border-color);\n\n\t/* Deselect State */\n\t--vs-dropdown-option--deselect-bg: var(--color-error);\n\t--vs-dropdown-option--deselect-color: #fff;\n\n\t/* Transitions */\n\t--vs-transition-duration: 0ms;\n\n\t/* Actions */\n\t--vs-actions-padding: 0 8px 0 8px;\n\t/* Override default vue-select styles */\n\tmin-height: calc(var(--default-clickable-area) - 2 * var(--border-width-input, 2px));\n\tmin-width: 260px;\n\t// 6px block-start reserves space for the floated label, matching\n\t// NcInputField (.input-field margin-block-start) so fields line up in a row.\n\tmargin: 6px 0 var(--default-grid-baseline);\n\n\t&.vs--open {\n\t\t--vs-border-width: var(--border-width-input-focused, 2px);\n\t}\n\n\t.vs__selected {\n\t\t// min-height (not height) so multi-line entries like NcSelectUsers chips can grow\n\t\tmin-height: calc(var(--default-clickable-area) - 2 * var(--vs-border-width) - var(--default-grid-baseline));\n\t\tmin-width: 0;\n\t\tmax-width: 100%;\n\t\tmargin: calc(var(--default-grid-baseline) / 2);\n\t\tpadding-block: 0;\n\t\tpadding-inline: 12px 8px;\n\t\tborder-radius: 16px !important;\n\t\tbackground: var(--color-primary-element-light);\n\t\tborder: none;\n\t}\n\n\t.vs__search {\n\t\t// NcTextField filling the search area; padding-end reserved for the actions overlay\n\t\twidth: 100%;\n\t\t--input-padding-end: calc(var(--default-clickable-area) + var(--default-grid-baseline));\n\n\t\t// Neutralize vue-select defaults on the wrapper div (no longer the native input).\n\t\t// The height reset also beats legacy global styles (e.g. bundled by the server)\n\t\t// that force a fixed height on `.vs__search` from the old native-input design.\n\t\tborder: none !important;\n\t\tmargin: 0 !important;\n\t\tpadding: 0 !important;\n\t\theight: auto !important;\n\t}\n\n\t// Force floating label when a value is selected (search input is empty but a value exists)\n\t.vs__selected-options:has(.vs__selected) .vs__search {\n\t\t.input-field__input + .input-field__label {\n\t\t\t--input-label-font-size: var(--font-size-small, 13px);\n\t\t\tline-height: 1.5;\n\t\t\tinset-block-start: calc(-1.5 * var(--input-label-font-size) / 2);\n\t\t\tfont-weight: 500;\n\t\t\tborder-radius: var(--default-grid-baseline) var(--default-grid-baseline) 0 0;\n\t\t\tbackground-color: var(--color-main-background);\n\t\t\tpadding-inline: var(--default-grid-baseline);\n\t\t\tmargin-inline: calc(var(--input-padding-start) - var(--default-grid-baseline)) calc(var(--input-padding-end) - var(--default-grid-baseline));\n\t\t\ttransition: height var(--animation-quick), inset-block-start var(--animation-quick), font-size var(--animation-quick), color var(--animation-quick);\n\t\t}\n\t}\n\n\t// Single mode: border is on NcTextField, dropdown-toggle is invisible\n\t&:not(.vs--multiple) .vs__dropdown-toggle {\n\t\tpadding: 0;\n\t\toverflow: visible;\n\t\tborder: none !important;\n\t\tbox-shadow: none !important;\n\t\tbackground: transparent;\n\t}\n\n\t// Anchor the absolutely-positioned actions to the control itself, so content\n\t// rendered below it inside .v-select (e.g. the helper text) does not shift\n\t// the caret's vertical centering.\n\t.vs__dropdown-toggle {\n\t\tposition: relative;\n\t}\n\n\t.vs__actions {\n\t\tposition: absolute;\n\t\tz-index: 999;\n\t\tinset-inline-end: 0;\n\t\ttop: 50%;\n\t\ttransform: translateY(-50%);\n\t\theight: 100%;\n\t\tmargin-block-start: 1px;\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t}\n\n\t.vs__clear {\n\t\tmargin-inline-end: 2px;\n\t}\n\n\t&.vs--open {\n\t\t// Remove bottom border-radius when dropdown is open\n\t\t.vs__search .input-field__input {\n\t\t\tborder-end-start-radius: 0 !important;\n\t\t\tborder-end-end-radius: 0 !important;\n\t\t}\n\t}\n\n\t&.vs--disabled {\n\t\t// Override vue-select's disabled background on all internal elements\n\t\t// to prevent stacking with NcInputField's own background\n\t\t.vs__clear,\n\t\t.vs__dropdown-toggle,\n\t\t.vs__open-indicator,\n\t\t.vs__open-indicator-button,\n\t\t.vs__search,\n\t\t.vs__selected {\n\t\t\tbackground-color: transparent;\n\t\t\tcolor: var(--color-text-maxcontrast);\n\t\t}\n\n\t\t// Lighter border in disabled state to match single mode (NcInputField uses --color-border-dark)\n\t\t.vs__dropdown-toggle {\n\t\t\t--input-border-box-shadow-light: 0 -1px var(--color-border-dark),\n\t\t\t\t0 0 0 1px color-mix(in srgb, var(--color-border-dark), 65% transparent);\n\t\t\t--input-border-box-shadow-dark: 0 1px var(--color-border-dark),\n\t\t\t\t0 0 0 1px color-mix(in srgb, var(--color-border-dark), 65% transparent);\n\t\t}\n\n\t\t.vs__clear,\n\t\t.vs__deselect {\n\t\t\tdisplay: none;\n\t\t}\n\t}\n\n\t&--no-wrap {\n\t\t.vs__dropdown-toggle {\n\t\t\toverflow: hidden;\n\t\t}\n\t\t.vs__selected-options {\n\t\t\tflex-wrap: nowrap;\n\t\t\toverflow: auto !important;\n\t\t\tmin-width: unset;\n\t\t\t.vs__selected {\n\t\t\t\tmin-width: unset;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Drop-up: the menu is detached above the select (calculatePosition leaves a\n\t// gap for the floating label, which stays in its usual top position),\n\t// so keep the regular fully-rounded borders instead of flattening the seam\n\t&--drop-up {\n\t\t&.vs--open {\n\t\t\t.vs__search .input-field__input {\n\t\t\t\tborder-end-start-radius: var(--border-radius-element) !important;\n\t\t\t\tborder-end-end-radius: var(--border-radius-element) !important;\n\t\t\t}\n\n\t\t\t// !important to beat the later-defined down-state open rule\n\t\t\t// (.vs--multiple.vs--open .vs__dropdown-toggle) of equal specificity\n\t\t\t&.vs--multiple .vs__dropdown-toggle {\n\t\t\t\tborder-end-start-radius: var(--border-radius-element) !important;\n\t\t\t\tborder-end-end-radius: var(--border-radius-element) !important;\n\t\t\t\t// Bottom is a regular outer edge here, not a divider seam\n\t\t\t\tborder-block-end-color: var(--color-main-text) !important;\n\t\t\t}\n\t\t}\n\t}\n\n\t.vs__selected-options {\n\t\t// If search is hidden, ensure that the height of the search is the same\n\t\tmin-height: unset;\n\n\t\t// Hide search from dom if unused to prevent unneeded flex wrap\n\t\t.vs__selected ~ .vs__search:has(.input-field__input[readonly]) {\n\t\t\tposition: absolute;\n\t\t}\n\t\tpadding: 0;\n\t\tborder: none;\n\t\toverflow: visible;\n\t}\n\n\t// Multi-select: border on dropdown-toggle (contains tags + input)\n\t// NcTextField is transparent; floating label via #header slot\n\t&.vs--multiple {\n\t\t// The multiple variant otherwise renders ~2px wider than the single one\n\t\t// and overflows its container; inset it by 1px on each side to align.\n\t\tmargin-inline: 1px;\n\n\t\t.vs__dropdown-toggle {\n\t\t\t// Use transparent border in closed state to reserve the same space\n\t\t\t// as the open state's real border, prevents layout jump on click\n\t\t\tborder: var(--border-width-input-focused, 2px) solid transparent;\n\t\t\tbox-shadow: var(--input-border-box-shadow);\n\t\t\t// Top padding for floating label clearance, no bottom padding\n\t\t\tpadding-block: calc(var(--default-grid-baseline) * 1.5) 0;\n\t\t\t// Left padding so tags don't overlap the border-radius curve,\n\t\t\t// right padding reserved for the actions overlay (chevron)\n\t\t\tpadding-inline: var(--default-grid-baseline) calc(var(--default-clickable-area) + var(--default-grid-baseline));\n\t\t\toverflow: visible;\n\t\t\tbackground: var(--color-main-background);\n\t\t}\n\n\t\t// Wider reservation when the clear button is shown next to the chevron\n\t\t&:has(.vs__clear) .vs__dropdown-toggle {\n\t\t\tpadding-inline-end: calc(2 * var(--default-clickable-area));\n\t\t}\n\n\t\t// When open, switch to visible border with subtle bottom divider\n\t\t&.vs--open .vs__dropdown-toggle {\n\t\t\tbox-shadow: none !important;\n\t\t\tborder-color: var(--color-main-text);\n\t\t\t// Subtle divider line between tags and dropdown (not fully transparent)\n\t\t\tborder-block-end-color: var(--color-border-maxcontrast);\n\t\t\tborder-end-start-radius: 0;\n\t\t\tborder-end-end-radius: 0;\n\t\t\toutline: 2px solid var(--color-main-background);\n\t\t}\n\n\t\t// Remove NcTextField border in multi mode, border is on dropdown-toggle\n\t\t.vs__search .input-field__input {\n\t\t\tbox-shadow: none !important;\n\t\t\tbackground: transparent;\n\t\t}\n\n\t\t// NcTextField shares flex row with tags, always inline, no absolute hiding.\n\t\t// No min-width: it may shrink fully so it never forces an empty wrap row\n\t\t// (matches vue-select's own search sizing)\n\t\t.vs__search {\n\t\t\twidth: 0;\n\t\t\tflex-grow: 1;\n\t\t\tmin-width: 0;\n\t\t}\n\n\t\t// No-wrap: clip overflow inside the toggle (needs to be here\n\t\t// for specificity to beat the overflow: visible above)\n\t\t&.select--no-wrap {\n\t\t\t.vs__dropdown-toggle {\n\t\t\t\toverflow: hidden;\n\t\t\t}\n\n\t\t\t.vs__actions {\n\t\t\t\t// Slight fade for non-wrap tags display\n\t\t\t\tbackground: linear-gradient(90deg, transparent, var(--color-main-background) 10%, var(--color-main-background) 100%);\n\t\t\t\tmargin-block: 0px;\n\t\t\t\tmargin-inline-end: 2px;\n\t\t\t\tborder-radius: var(--border-radius-element);\n\t\t\t\theight: calc(100% - 6px);\n\t\t\t}\n\t\t}\n\n\t\t// No label margin needed, label is via #header\n\t\t.vs__search .input-field {\n\t\t\tmargin-block-start: 0;\n\t\t}\n\n\t\t// Match NcTextField height to tag row height for consistent toggle sizing\n\t\t.vs__search .input-field__main-wrapper {\n\t\t\theight: calc(var(--default-clickable-area) - 2 * var(--vs-border-width) - var(--default-grid-baseline));\n\t\t\tmargin: calc(var(--default-grid-baseline) / 2) 0;\n\t\t}\n\n\t\t// Label: centered inside toggle when empty (placeholder-like),\n\t\t// floats above border when has value or open (matches NcInputField)\n\t\t.select__label {\n\t\t\tposition: absolute;\n\t\t\tz-index: 1;\n\t\t\tinset-inline-start: var(--border-width-input-focused, 2px);\n\t\t\t// Center vertically regardless of toggle height\n\t\t\ttop: 50%;\n\t\t\ttransform: translateY(-50%);\n\t\t\tfont-size: var(--default-font-size);\n\t\t\tmargin-inline: var(--border-radius-element);\n\t\t\tcolor: var(--color-text-maxcontrast);\n\t\t\tpointer-events: none;\n\t\t\twhite-space: nowrap;\n\t\t\toverflow: hidden;\n\t\t\ttext-overflow: ellipsis;\n\t\t\tmax-width: calc(100% - var(--clickable-area-large));\n\t\t\ttransition: top var(--animation-quick), transform var(--animation-quick), font-size var(--animation-quick), font-weight var(--animation-quick), background-color var(--animation-quick) var(--animation-slow);\n\t\t}\n\n\t\t// Float label when has tags or dropdown is open\n\t\t&:has(.vs__selected) .select__label,\n\t\t&.vs--open .select__label {\n\t\t\t--input-label-font-size: var(--font-size-small, 13px);\n\t\t\tfont-size: var(--input-label-font-size);\n\t\t\tline-height: 1.5;\n\t\t\t// Match NcInputField: half the line-height above the border\n\t\t\ttop: calc(-1.5 * var(--input-label-font-size) / 2);\n\t\t\ttransform: none;\n\t\t\tfont-weight: 500;\n\t\t\tborder-radius: var(--default-grid-baseline) var(--default-grid-baseline) 0 0;\n\t\t\tbackground-color: var(--color-main-background);\n\t\t\tpadding-inline: var(--default-grid-baseline);\n\t\t\tmargin-inline: calc(var(--border-radius-element) - var(--default-grid-baseline));\n\t\t\ttransition: top var(--animation-quick), transform var(--animation-quick), font-size var(--animation-quick), font-weight var(--animation-quick), background-color var(--animation-quick);\n\t\t}\n\t}\n\n\t&.vs--single {\n\t\t// In single mode, overlay the selected value on top of the NcTextField input area\n\t\t// so it appears inside the border (which is on the NcTextField, not the toggle)\n\t\t.vs__selected-options {\n\t\t\tposition: relative;\n\t\t\tflex-wrap: nowrap;\n\t\t\t// Ensure height even when search input is hidden (vs--unsearchable)\n\t\t\tmin-height: var(--default-clickable-area);\n\t\t}\n\n\t\t.vs__selected {\n\t\t\tposition: absolute;\n\t\t\t// Skip the label clearance so the overlay covers only the input box,\n\t\t\t// keeping (multi-line) content like NcSelectUsers centered on the input\n\t\t\t// (6px = NcInputField .input-field margin-block-start)\n\t\t\tinset-block: 6px 0;\n\t\t\tinset-inline-start: 0;\n\t\t\tinset-inline-end: 0;\n\t\t\tmargin: 0;\n\t\t\tz-index: 2; // above vs__search (z-index: 1 from vue-select default)\n\t\t\tpointer-events: none;\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tpadding-block: 0;\n\t\t\t// Match the input text position: main-wrapper padding (border width) + input padding\n\t\t\tpadding-inline: calc(var(--border-radius-element) + var(--border-width-input-focused, 2px)) var(--input-padding-end, calc(var(--default-clickable-area) + var(--default-grid-baseline)));\n\t\t\tbackground: unset !important;\n\t\t\tborder: none;\n\t\t\tborder-radius: 0;\n\t\t\theight: unset;\n\t\t\tmin-height: unset;\n\t\t\tfont-size: var(--default-font-size);\n\t\t\tcolor: var(--color-main-text);\n\t\t\twhite-space: nowrap;\n\t\t\toverflow: hidden;\n\t\t\ttext-overflow: ellipsis;\n\t\t}\n\n\t\t// No label clearance to skip when the label is external\n\t\t&:has(.input-field--label-outside) .vs__selected {\n\t\t\tinset-block-start: 0;\n\t\t}\n\n\t\t// Extra padding when clear button visible (clear + chevron need more space)\n\t\t&:has(.vs__clear) .vs__selected {\n\t\t\tpadding-inline-end: calc(2 * var(--default-clickable-area));\n\t\t}\n\n\t\t&.vs--loading,\n\t\t&.vs--open {\n\t\t\t.vs__selected {\n\t\t\t\t// Fix color to be accessible while typing\n\t\t\t\topacity: 0.4;\n\t\t\t}\n\t\t}\n\n\t\t// Hide the selected value as soon as the user types a query\n\t\t// (restores vue-select's default, overridden by our display: flex above)\n\t\t&.vs--searching .vs__selected {\n\t\t\tdisplay: none;\n\t\t}\n\t}\n}\n\n// Dropdown menu is teleported to <body>, so it can't live under the\n// `.nc-select` root scope. The `.nc-select__dropdown` class (added in\n// calculatePosition) scopes it instead, so these styles and CSS variables\n// only affect our menus and never leak to other vue-select instances.\n.nc-select__dropdown.vs__dropdown-menu {\n\t--vs-border-color: var(--color-border-maxcontrast);\n\t--vs-border-style: solid;\n\t--vs-border-radius: var(--border-radius-element);\n\t--vs-dropdown-bg: var(--color-main-background);\n\t--vs-dropdown-color: var(--color-main-text);\n\t--vs-dropdown-option-padding: 8px 20px;\n\t--vs-dropdown-option--active-bg: var(--color-background-hover);\n\t--vs-dropdown-option--active-color: var(--color-main-text);\n\t--vs-dropdown-option--kb-focus-box-shadow: inset 0px 0px 0px 2px var(--color-border-maxcontrast);\n\t--vs-dropdown-option--deselect-bg: var(--color-error);\n\t--vs-dropdown-option--deselect-color: #fff;\n\tborder-width: var(--border-width-input-focused) !important;\n\tborder-color: var(--color-main-text) !important;\n\toutline: none !important;\n\tbox-shadow:\n\t\t-2px 0 0 var(--color-main-background), // Right\n\t\t0 2px 0 var(--color-main-background), // Bottom\n\t\t2px 0 0 var(--color-main-background), // Left\n\t\t!important;\n\tpadding: 4px !important;\n\n\t&--floating {\n\t\t/* Fallback styles overidden by programmatically set inline styles */\n\t\twidth: max-content;\n\t\tposition: absolute;\n\t\ttop: 0;\n\t\tinset-inline-start: 0;\n\n\t\t// Top placement: the menu is detached from the select (gap for the\n\t\t// floating label), so it keeps a full border on all sides\n\t\t&-placement-top {\n\t\t\tborder-radius: var(--vs-border-radius) !important;\n\t\t\tborder-top-style: var(--vs-border-style) !important;\n\t\t\tbox-shadow:\n\t\t\t\t0 -2px 0 var(--color-main-background), // Top\n\t\t\t\t-2px 0 0 var(--color-main-background), // Right\n\t\t\t\t0 2px 0 var(--color-main-background), // Bottom\n\t\t\t\t2px 0 0 var(--color-main-background), // Left\n\t\t\t\t!important\n\t\t}\n\t}\n\n\t.vs__dropdown-option {\n\t\tborder-radius: 6px !important;\n\t}\n\n\t.vs__no-options {\n\t\tcolor: var(--color-text-maxcontrast) !important;\n\t}\n}\n\n// Border for .vs__dropdown-toggle, inlined from inputLikeBorder mixin\n// because the mixin's @media #{&} produces doubled selectors when nested.\n.nc-select.v-select.select .vs__dropdown-toggle {\n\t--input-border-box-shadow-light: 0 -1px var(--vs-border-color),\n\t\t0 0 0 1px color-mix(in srgb, var(--vs-border-color), 65% transparent);\n\t--input-border-box-shadow-dark: 0 -1px var(--vs-border-color),\n\t\t0 0 0 1px color-mix(in srgb, var(--vs-border-color), 65% transparent);\n\t--input-border-box-shadow: var(--input-border-box-shadow-light);\n\tborder: none;\n\tborder-radius: var(--border-radius-element);\n\tbox-shadow: var(--input-border-box-shadow);\n}\n\n// Hover: use .vs--disabled on parent (toggle div never has [disabled] attribute)\n.nc-select.v-select.select:not(.vs--disabled) .vs__dropdown-toggle:hover {\n\tbox-shadow: 0 0 0 1px var(--vs-border-color);\n}\n\n@media (prefers-color-scheme: dark) {\n\t.nc-select.v-select.select .vs__dropdown-toggle {\n\t\t--input-border-box-shadow: var(--input-border-box-shadow-dark);\n\t}\n}\n\n[data-theme-dark] .nc-select.v-select.select .vs__dropdown-toggle {\n\t--input-border-box-shadow: var(--input-border-box-shadow-dark);\n}\n\n[data-theme-light] .nc-select.v-select.select .vs__dropdown-toggle {\n\t--input-border-box-shadow: var(--input-border-box-shadow-light);\n}\n\n.select--legacy.nc-select.v-select.select .vs__dropdown-toggle {\n\tbox-shadow: 0 0 0 1px var(--vs-border-color);\n\n\t&:hover:not([disabled]) {\n\t\tbox-shadow: 0 0 0 2px var(--vs-border-color);\n\t}\n}\n</style>\n"],"names":["NcTextField","Close","_openBlock","_createBlock","_mergeProps","_withCtx","_createVNode","_normalizeClass","_renderSlot","_normalizeProps","_guardReactiveProps","_createElementVNode","_createElementBlock","_createTextVNode","_renderList"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"NcSelect.mjs","sources":["../../src/components/NcSelect/NcSelect.vue"],"sourcesContent":["<!--\n - SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<docs>\n### Description\n\nGeneral purpose multiselect component.\n\n### Basic 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<NcSelect v-bind=\"props\"\n\t\t\t\tv-model=\"props.value\" />\n\t\t</div>\n\t</div>\n</template>\n\n<script>\nconst selectArray = [\n\t{\n\t\tprops: {\n\t\t\tinputLabel: 'Simple',\n\t\t\toptions: [\n\t\t\t\t'foo',\n\t\t\t\t'bar',\n\t\t\t\t'baz',\n\t\t\t\t'qux',\n\t\t\t\t'quux',\n\t\t\t],\n\t\t},\n\t},\n\n\t{\n\t\tprops: {\n\t\t\tinputLabel: 'With helper text',\n\t\t\thelperText: 'Choose the option that fits best',\n\t\t\toptions: [\n\t\t\t\t'foo',\n\t\t\t\t'bar',\n\t\t\t\t'baz',\n\t\t\t],\n\t\t},\n\t},\n\n\t{\n\t\tprops: {\n\t\t\tinputLabel: 'With error',\n\t\t\thelperText: 'This selection is required',\n\t\t\terror: true,\n\t\t\toptions: [\n\t\t\t\t'foo',\n\t\t\t\t'bar',\n\t\t\t\t'baz',\n\t\t\t],\n\t\t},\n\t},\n\n\t{\n\t\tprops: {\n\t\t\tinputLabel: 'Simple (top placement)',\n\t\t\tplacement: 'top',\n\t\t\toptions: [\n\t\t\t\t'foo',\n\t\t\t\t'bar',\n\t\t\t\t'baz',\n\t\t\t\t'qux',\n\t\t\t\t'quux',\n\t\t\t],\n\t\t},\n\t},\n\n\t{\n\t\tprops: {\n\t\t\tinputLabel: 'Multiple (with placeholder)',\n\t\t\tmultiple: true,\n\t\t\tplaceholder: 'Select multiple options',\n\t\t\toptions: [\n\t\t\t\t'foo',\n\t\t\t\t'bar',\n\t\t\t\t'baz',\n\t\t\t\t'qux',\n\t\t\t\t'quux',\n\t\t\t],\n\t\t},\n\t},\n\n\t{\n\t\tprops: {\n\t\t\tinputLabel: 'Multiple (objects, pre-selected, 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: 'foo',\n\t\t\t\t\tlabel: 'Foo',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: 'bar',\n\t\t\t\t\tlabel: 'Bar',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: 'baz',\n\t\t\t\t\tlabel: 'Baz',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: 'qux',\n\t\t\t\t\tlabel: 'Qux',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: 'quux',\n\t\t\t\t\tlabel: 'Quux',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: 'corge',\n\t\t\t\t\tlabel: 'Corge',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: 'grault',\n\t\t\t\t\tlabel: 'Grault',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: 'garply',\n\t\t\t\t\tlabel: 'Garply',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: 'waldo',\n\t\t\t\t\tlabel: 'Waldo',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: 'fred',\n\t\t\t\t\tlabel: 'Fred',\n\t\t\t\t},\n\t\t\t],\n\t\t\tvalue: [\n\t\t\t\t{\n\t\t\t\t\tid: 'foo',\n\t\t\t\t\tlabel: 'Foo',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tid: 'bar',\n\t\t\t\t\tlabel: 'Bar',\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(2, 1fr);\n\tgap: 10px;\n}\n\n.container {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px 0;\n}\n</style>\n```\n\n### Pre-selected and clearable\n\n```vue\n<template>\n\t<div class=\"grid\">\n\t\t<div class=\"container\">\n\t\t\t<NcSelect v-model=\"singleValue\"\n\t\t\t\tinput-label=\"Clearable single\"\n\t\t\t\t:options=\"options\"\n\t\t\t\tclearable />\n\t\t</div>\n\t\t<div class=\"container\">\n\t\t\t<NcSelect v-model=\"singlePlaceholder\"\n\t\t\t\tinput-label=\"With placeholder\"\n\t\t\t\tplaceholder=\"Search for something...\"\n\t\t\t\t:options=\"options\" />\n\t\t</div>\n\t</div>\n</template>\n\n<script>\nexport default {\n\tdata() {\n\t\treturn {\n\t\t\toptions: ['foo', 'bar', 'baz', 'qux', 'quux'],\n\t\t\tsingleValue: 'bar',\n\t\t\tsinglePlaceholder: null,\n\t\t}\n\t},\n}\n</script>\n\n<style>\n.grid {\n\tdisplay: grid;\n\tgrid-template-columns: repeat(2, 1fr);\n\tgap: 10px;\n}\n\n.container {\n\tdisplay: flex;\n\tflex-direction: column;\n}\n</style>\n```\n\n### Disabled state\n\n```vue\n<template>\n\t<div class=\"grid\">\n\t\t<div class=\"container\">\n\t\t\t<NcSelect v-model=\"singleValue\"\n\t\t\t\tinput-label=\"Disabled single\"\n\t\t\t\t:options=\"options\"\n\t\t\t\tdisabled />\n\t\t</div>\n\t\t<div class=\"container\">\n\t\t\t<NcSelect v-model=\"multiValue\"\n\t\t\t\tinput-label=\"Disabled multi\"\n\t\t\t\t:options=\"options\"\n\t\t\t\tmultiple\n\t\t\t\tdisabled />\n\t\t</div>\n\t</div>\n</template>\n\n<script>\nexport default {\n\tdata() {\n\t\treturn {\n\t\t\toptions: ['foo', 'bar', 'baz'],\n\t\t\tsingleValue: 'foo',\n\t\t\tmultiValue: ['foo', 'bar'],\n\t\t}\n\t},\n}\n</script>\n\n<style>\n.grid {\n\tdisplay: grid;\n\tgrid-template-columns: repeat(2, 1fr);\n\tgap: 10px;\n}\n\n.container {\n\tdisplay: flex;\n\tflex-direction: column;\n}\n</style>\n```\n\n### Label outside\n\n```vue\n<template>\n\t<div class=\"grid\">\n\t\t<div class=\"container\">\n\t\t\t<label for=\"ext-single\">External label (single)</label>\n\t\t\t<NcSelect v-model=\"singleValue\"\n\t\t\t\tinput-id=\"ext-single\"\n\t\t\t\tlabel-outside\n\t\t\t\tplaceholder=\"Pick an option\"\n\t\t\t\t:options=\"options\" />\n\t\t</div>\n\t\t<div class=\"container\">\n\t\t\t<label for=\"ext-multi\">External label (multi)</label>\n\t\t\t<NcSelect v-model=\"multiValue\"\n\t\t\t\tinput-id=\"ext-multi\"\n\t\t\t\tlabel-outside\n\t\t\t\t:options=\"options\"\n\t\t\t\tmultiple />\n\t\t</div>\n\t</div>\n</template>\n\n<script>\nexport default {\n\tdata() {\n\t\treturn {\n\t\t\toptions: ['foo', 'bar', 'baz', 'qux', 'quux'],\n\t\t\tsingleValue: null,\n\t\t\tmultiValue: [],\n\t\t}\n\t},\n}\n</script>\n\n<style>\n.grid {\n\tdisplay: grid;\n\tgrid-template-columns: repeat(2, 1fr);\n\tgap: 10px;\n}\n\n.container {\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n}\n</style>\n```\n\n### Native form validation example\n\n```vue\n<template>\n\t<div class=\"container\">\n\t\t<form class=\"container__form\" @submit.prevent>\n\t\t\t<NcSelect class=\"container__select\"\n\t\t\t\tinput-label=\"Require a selection\"\n\t\t\t\t:options=\"options\"\n\t\t\t\tv-model=\"singleValue\"\n\t\t\t\trequired />\n\t\t\t<NcButton type=\"submit\">Submit</NcButton>\n\t\t</form>\n\n\t\t<form class=\"container__form\" @submit.prevent>\n\t\t\t<NcSelect class=\"container__select\"\n\t\t\t\tinput-label=\"Require at least one selection\"\n\t\t\t\t:options=\"options\"\n\t\t\t\tv-model=\"multiValue\"\n\t\t\t\tmultiple\n\t\t\t\trequired />\n\t\t\t<NcButton type=\"submit\">Submit</NcButton>\n\t\t</form>\n\t</div>\n</template>\n\n<script>\nexport default {\n\tdata() {\n\t\treturn {\n\t\t\toptions: ['foo', 'bar', 'baz', 'qux', 'quux'],\n\t\t\tsingleValue: null,\n\t\t\tmultiValue: [],\n\t\t}\n\t},\n}\n</script>\n\n<style>\n.container {\n\tdisplay: flex;\n\tgap: 0 12px;\n}\n\n.container__form {\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: flex-end;\n\twidth: 100%;\n\tgap: 8px 0;\n}\n\n.container__select {\n\twidth: 100%;\n}\n</style>\n```\n\n### No wrap example\n\nThe `noWrap` prop is set to `true` and the `max-width` of the multiselect\nparent container is limited to `350px`\n\n```vue\n<template>\n\t<div class=\"grid\">\n\t\t<div class=\"container\">\n\t\t\t<NcSelect :no-wrap=\"false\"\n\t\t\t\tv-bind=\"data1.props\"\n\t\t\t\tv-model=\"data1.props.value\" />\n\t\t</div>\n\t\t<div class=\"container\">\n\t\t\t<NcSelect :no-wrap=\"true\"\n\t\t\t\tv-bind=\"data2.props\"\n\t\t\t\tv-model=\"data2.props.value\" />\n\t\t</div>\n\t</div>\n</template>\n\n<script>\nconst data1 = {\n\tprops: {\n\t\tinputLabel: 'Wrapped (Default)',\n\t\tmultiple: true,\n\t\tkeepOpen: true,\n\t\toptions: [\n\t\t\t'foo',\n\t\t\t'bar',\n\t\t\t'baz',\n\t\t\t'qux',\n\t\t\t'quux',\n\t\t\t'corge',\n\t\t\t'grault',\n\t\t\t'garply',\n\t\t\t'waldo',\n\t\t\t'fred',\n\t\t],\n\t\tvalue: [\n\t\t\t'foo',\n\t\t\t'bar',\n\t\t\t'baz',\n\t\t\t'qux',\n\t\t\t'quux',\n\t\t\t'corge',\n\t\t\t'grault',\n\t\t\t'garply',\n\t\t\t'waldo',\n\t\t\t'fred',\n\t\t],\n\t},\n}\n\nconst data2 = {\n\tprops: {\n\t\tinputLabel: 'Not wrapped',\n\t\tkeepOpen: true,\n\t\tmultiple: true,\n\t\toptions: [\n\t\t\t'foo',\n\t\t\t'bar',\n\t\t\t'baz',\n\t\t\t'qux',\n\t\t\t'quux',\n\t\t\t'corge',\n\t\t\t'grault',\n\t\t\t'garply',\n\t\t\t'waldo',\n\t\t\t'fred',\n\t\t],\n\t\tvalue: [\n\t\t\t'foo',\n\t\t\t'bar',\n\t\t\t'baz',\n\t\t\t'qux',\n\t\t\t'quux',\n\t\t\t'corge',\n\t\t\t'grault',\n\t\t\t'garply',\n\t\t\t'waldo',\n\t\t\t'fred',\n\t\t],\n\t},\n}\n\nexport default {\n\tdata() {\n\t\treturn {\n\t\t\tdata1,\n\t\t\tdata2,\n\t\t}\n\t},\n}\n</script>\n\n<style>\n.grid {\n\tdisplay: grid;\n\tgrid-template-columns: repeat(1, 1fr);\n\tgap: 10px;\n}\n\n.container {\n\tmax-width: 350px;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 2px 0;\n}\n</style>\n```\n</docs>\n\n<template>\n\t<VueSelect\n\t\tclass=\"select nc-select\"\n\t\t:class=\"{\n\t\t\t'select--legacy': isLegacy,\n\t\t\t'select--no-wrap': noWrap,\n\t\t}\"\n\t\tv-bind=\"propsToForward\"\n\t\t@search=\"search = $event\"\n\t\t@update:modelValue=\"$emit('update:modelValue', $event)\">\n\t\t<template v-if=\"multiple && !labelOutside && inputLabel\" #header>\n\t\t\t<label\n\t\t\t\t:for=\"inputId\"\n\t\t\t\tclass=\"select__label\">\n\t\t\t\t{{ inputLabel }}\n\t\t\t</label>\n\t\t</template>\n\t\t<template #search=\"{ attributes, events }\">\n\t\t\t<!--\n\t\t\t\tvue-select's `attributes`/`events` are its search-slot contract, not\n\t\t\t\tHTML pass-through, so we forward only the combobox a11y attributes and\n\t\t\t\tevents one by one. This skips `attributes.ref` (a vue-select template\n\t\t\t\tref) and lets our own `modelValue`, `placeholder`, `label` and\n\t\t\t\t`disabled` win over their vue-select equivalents.\n\t\t\t\tNo placeholder when: multi mode (select__label is the placeholder) or a\n\t\t\t\tvalue is selected (the vs__selected overlay shows it instead).\n\t\t\t-->\n\t\t\t<NcTextField\n\t\t\t\t:id=\"attributes.id\"\n\t\t\t\tclass=\"vs__search\"\n\t\t\t\t:class=\"[inputClass]\"\n\t\t\t\t:type=\"attributes.type\"\n\t\t\t\t:modelValue=\"attributes.value\"\n\t\t\t\t:placeholder=\"multiple || modelValue ? '' : (placeholder || '')\"\n\t\t\t\t:label=\"!labelOutside && !multiple && inputLabel ? inputLabel : ''\"\n\t\t\t\t:labelOutside=\"labelOutside || multiple\"\n\t\t\t\t:disabled=\"disabled\"\n\t\t\t\t:required=\"inputRequired\"\n\t\t\t\t:role=\"attributes.role\"\n\t\t\t\t:tabindex=\"attributes.tabindex\"\n\t\t\t\t:readonly=\"attributes.readonly\"\n\t\t\t\t:autocomplete=\"attributes.autocomplete\"\n\t\t\t\t:aria-label=\"attributes['aria-label']\"\n\t\t\t\t:aria-describedby=\"[attributes['aria-describedby'], helperText ? `${inputId}-helper-text` : null].filter(Boolean).join(' ') || undefined\"\n\t\t\t\t:aria-autocomplete=\"attributes['aria-autocomplete']\"\n\t\t\t\t:aria-controls=\"attributes['aria-controls']\"\n\t\t\t\t:aria-owns=\"attributes['aria-owns']\"\n\t\t\t\t:aria-expanded=\"attributes['aria-expanded']\"\n\t\t\t\t:aria-activedescendant=\"attributes['aria-activedescendant']\"\n\t\t\t\t@keydown=\"events.keydown\"\n\t\t\t\t@keypress=\"events.keypress\"\n\t\t\t\t@focus=\"events.focus\"\n\t\t\t\t@blur=\"events.blur\"\n\t\t\t\t@compositionstart=\"events.compositionstart\"\n\t\t\t\t@compositionend=\"events.compositionend\"\n\t\t\t\t@update:modelValue=\"events.input({ target: { value: $event } })\" />\n\t\t</template>\n\t\t<template #open-indicator=\"{ attributes }\">\n\t\t\t<ChevronDown\n\t\t\t\tv-bind=\"attributes\"\n\t\t\t\tfillColor=\"var(--vs-controls-color)\"\n\t\t\t\t:style=\"{\n\t\t\t\t\tcursor: !disabled ? 'pointer' : null,\n\t\t\t\t}\"\n\t\t\t\t:size=\"20\" />\n\t\t</template>\n\t\t<template #option=\"option\">\n\t\t\t<!-- @slot Customize how a option is rendered. -->\n\t\t\t<slot name=\"option\" v-bind=\"option\">\n\t\t\t\t<NcEllipsisedOption\n\t\t\t\t\t:name=\"String(option[localLabel])\"\n\t\t\t\t\t:search=\"search\" />\n\t\t\t</slot>\n\t\t</template>\n\t\t<template #selected-option=\"selectedOption\">\n\t\t\t<!-- @slot Customize how a selected option is rendered -->\n\t\t\t<slot name=\"selected-option\" v-bind=\"selectedOption\">\n\t\t\t\t<NcEllipsisedOption\n\t\t\t\t\t:name=\"String(selectedOption[localLabel])\"\n\t\t\t\t\t:search=\"search\" />\n\t\t\t</slot>\n\t\t</template>\n\t\t<template #spinner=\"spinner\">\n\t\t\t<NcLoadingIcon v-if=\"spinner.loading\" />\n\t\t</template>\n\t\t<template #no-options>\n\t\t\t{{ t('No results') }}\n\t\t</template>\n\t\t<!-- Helper text beneath the control, plus any consumer-provided footer slot -->\n\t\t<template v-if=\"helperText || $slots.footer\" #footer=\"data\">\n\t\t\t<p\n\t\t\t\tv-if=\"helperText\"\n\t\t\t\t:id=\"`${inputId}-helper-text`\"\n\t\t\t\tclass=\"select__helper-text\"\n\t\t\t\t:class=\"{\n\t\t\t\t\t'select__helper-text--error': error,\n\t\t\t\t\t'select__helper-text--success': success,\n\t\t\t\t}\">\n\t\t\t\t<NcIconSvgWrapper\n\t\t\t\t\tv-if=\"success\"\n\t\t\t\t\tclass=\"select__helper-text-icon\"\n\t\t\t\t\t:path=\"mdiCheck\"\n\t\t\t\t\tinline />\n\t\t\t\t<NcIconSvgWrapper\n\t\t\t\t\tv-else-if=\"error\"\n\t\t\t\t\tclass=\"select__helper-text-icon\"\n\t\t\t\t\t:path=\"mdiAlertCircleOutline\"\n\t\t\t\t\tinline />\n\t\t\t\t{{ helperText }}\n\t\t\t</p>\n\t\t\t<slot name=\"footer\" v-bind=\"data\" />\n\t\t</template>\n\t\t<template v-for=\"name in forwardedSlots()\" :key=\"name\" #[name]=\"data\">\n\t\t\t<!-- @slot Any combination of slots from https://vue-select.org/api/slots.html -->\n\t\t\t<slot :name=\"name\" v-bind=\"data\" />\n\t\t</template>\n\t</VueSelect>\n</template>\n\n<script>\nimport {\n\tautoUpdate,\n\tcomputePosition,\n\tflip,\n\tlimitShift,\n\toffset,\n\tshift,\n} from '@floating-ui/dom'\nimport { mdiAlertCircleOutline, mdiCheck } from '@mdi/js'\nimport { VueSelect } from '@nextcloud/vue-select'\nimport { h, warn } from 'vue'\nimport ChevronDown from 'vue-material-design-icons/ChevronDown.vue'\nimport Close from 'vue-material-design-icons/Close.vue'\nimport NcEllipsisedOption from '../NcEllipsisedOption/NcEllipsisedOption.vue'\nimport NcIconSvgWrapper from '../NcIconSvgWrapper/NcIconSvgWrapper.vue'\nimport NcLoadingIcon from '../NcLoadingIcon/NcLoadingIcon.vue'\nimport NcTextField from '../NcTextField/NcTextField.vue'\nimport { t } from '../../l10n.ts'\nimport { createElementId } from '../../utils/createElementId.ts'\nimport { isLegacy } from '../../utils/legacy.ts'\n\nexport default {\n\tname: 'NcSelect',\n\n\tcomponents: {\n\t\tChevronDown,\n\t\tNcEllipsisedOption,\n\t\tNcIconSvgWrapper,\n\t\tNcLoadingIcon,\n\t\tNcTextField,\n\t\tVueSelect,\n\t},\n\n\tprops: {\n\t\t// Add VueSelect props to $props\n\t\t...VueSelect.props,\n\t\t...VueSelect.mixins.reduce((allProps, mixin) => ({ ...allProps, ...mixin.props }), {}),\n\n\t\t/**\n\t\t * `aria-label` for the clear input button\n\t\t */\n\t\tariaLabelClearSelected: {\n\t\t\ttype: String,\n\t\t\tdefault: t('Clear selected'),\n\t\t},\n\n\t\t/**\n\t\t * `aria-label` for the search input\n\t\t *\n\t\t * A descriptive `inputLabel` is preferred as this is not visible.\n\t\t */\n\t\tariaLabelCombobox: {\n\t\t\ttype: String,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * `aria-label` for the listbox element\n\t\t */\n\t\tariaLabelListbox: {\n\t\t\ttype: String,\n\t\t\tdefault: t('Options'),\n\t\t},\n\n\t\t/**\n\t\t * Allows to customize the `aria-label` for the deselect-option button\n\t\t * The default is \"Deselect \" + optionLabel\n\t\t *\n\t\t * @type {(optionLabel: string) => string}\n\t\t */\n\t\tariaLabelDeselectOption: {\n\t\t\ttype: Function,\n\t\t\tdefault: (optionLabel) => t('Deselect {option}', { option: optionLabel }),\n\t\t},\n\n\t\t/**\n\t\t * Append the dropdown element to the end of the body\n\t\t * and size/position it dynamically.\n\t\t *\n\t\t * @see https://vue-select.org/api/props.html#appendtobody\n\t\t */\n\t\tappendToBody: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * When `appendToBody` is true, this function is responsible for\n\t\t * positioning the drop down list.\n\t\t *\n\t\t * If a function is returned from `calculatePosition`, it will\n\t\t * be called when the drop down list is removed from the DOM.\n\t\t * This allows for any garbage collection you may need to do.\n\t\t *\n\t\t * @see https://vue-select.org/api/props.html#calculateposition\n\t\t */\n\t\tcalculatePosition: {\n\t\t\ttype: Function,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Keep the dropdown open after selecting an option.\n\t\t *\n\t\t * @default false\n\t\t * @since 8.25.0\n\t\t */\n\t\tkeepOpen: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Replace default vue-select components\n\t\t *\n\t\t * @see https://vue-select.org/api/props.html#components\n\t\t */\n\t\tcomponents: {\n\t\t\ttype: Object,\n\t\t\tdefault: () => ({\n\t\t\t\tDeselect: {\n\t\t\t\t\trender: () => h(Close, {\n\t\t\t\t\t\tsize: 20,\n\t\t\t\t\t\tfillColor: 'var(--vs-controls-color)',\n\t\t\t\t\t\tstyle: [\n\t\t\t\t\t\t\t{ cursor: 'pointer' },\n\t\t\t\t\t\t],\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t}),\n\t\t},\n\n\t\t/**\n\t\t * Sets the maximum number of options to display in the dropdown list\n\t\t */\n\t\tlimit: {\n\t\t\ttype: Number,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Disable the component\n\t\t *\n\t\t * @see https://vue-select.org/api/props.html#disabled\n\t\t */\n\t\tdisabled: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Determines whether the dropdown should be open.\n\t\t * Receives the component instance as the only argument.\n\t\t *\n\t\t * @see https://vue-select.org/api/props.html#dropdownshouldopen\n\t\t */\n\t\tdropdownShouldOpen: {\n\t\t\ttype: Function,\n\t\t\tdefault: ({ noDrop, open }) => {\n\t\t\t\treturn noDrop ? false : open\n\t\t\t},\n\t\t},\n\n\t\t/**\n\t\t * Callback to determine if the provided option should\n\t\t * match the current search text. Used to determine\n\t\t * if the option should be displayed.\n\t\t *\n\t\t * Defaults to the internal vue-select function documented at the link\n\t\t * below\n\t\t *\n\t\t * @see https://vue-select.org/api/props.html#filterby\n\t\t */\n\t\tfilterBy: {\n\t\t\ttype: Function,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Class for the `input`\n\t\t *\n\t\t * Necessary for use in NcActionInput\n\t\t */\n\t\tinputClass: {\n\t\t\ttype: [String, Object],\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Input element id\n\t\t */\n\t\tinputId: {\n\t\t\ttype: String,\n\t\t\tdefault: () => createElementId(),\n\t\t},\n\n\t\t/**\n\t\t * Visible label for the input element\n\t\t */\n\t\tinputLabel: {\n\t\t\ttype: String,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Additional helper text shown beneath the select.\n\t\t */\n\t\thelperText: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Toggle the error state, styling the helper text as an error.\n\t\t */\n\t\terror: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Toggle the success state, styling the helper text as a success.\n\t\t */\n\t\tsuccess: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Pass true if you are using an external label\n\t\t */\n\t\tlabelOutside: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Display a visible border around dropdown options\n\t\t * which have keyboard focus\n\t\t */\n\t\tkeyboardFocusBorder: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Key of the displayed label for object options\n\t\t *\n\t\t * Defaults to the internal vue-select string documented at the link\n\t\t * below\n\t\t *\n\t\t * @see https://vue-select.org/api/props.html#label\n\t\t */\n\t\tlabel: {\n\t\t\ttype: String,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Show the loading icon\n\t\t *\n\t\t * @see https://vue-select.org/api/props.html#loading\n\t\t */\n\t\tloading: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Allow selection of multiple options\n\t\t *\n\t\t * @see https://vue-select.org/api/props.html#multiple\n\t\t */\n\t\tmultiple: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Disable automatic wrapping when selected options overflow the width\n\t\t */\n\t\tnoWrap: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Array of options\n\t\t *\n\t\t * @type {Array<string | number | Record<string | number, any>>}\n\t\t *\n\t\t * @see https://vue-select.org/api/props.html#options\n\t\t */\n\t\toptions: {\n\t\t\ttype: Array,\n\t\t\tdefault: () => [],\n\t\t},\n\n\t\t/**\n\t\t * Placeholder text\n\t\t *\n\t\t * @see https://vue-select.org/api/props.html#placeholder\n\t\t */\n\t\tplaceholder: {\n\t\t\ttype: String,\n\t\t\tdefault: '',\n\t\t},\n\n\t\t/**\n\t\t * Customized component's response to keydown events while the search input has focus\n\t\t *\n\t\t * @see https://vue-select.org/guide/keydown.html#mapkeydown\n\t\t */\n\t\tmapKeydown: {\n\t\t\ttype: Function,\n\t\t\t/**\n\t\t\t * Patched Vue-Select keydown events handlers map to stop Escape propagation in open select\n\t\t\t *\n\t\t\t * @param {Record<number, (event: KeyboardEvent) => void>} map - Mapped keyCode to handlers { <keyCode>:<callback> }\n\t\t\t * @param {import('vue').ComponentPublicInstance} vm - VueSelect instance\n\t\t\t * @return {Record<number, (event: KeyboardEvent) => void>} patched keydown event handlers\n\t\t\t */\n\t\t\tdefault(map, vm) {\n\t\t\t\treturn {\n\t\t\t\t\t...map,\n\t\t\t\t\t/**\n\t\t\t\t\t * Patched Escape handler to stop propagation from open select\n\t\t\t\t\t *\n\t\t\t\t\t * @param {KeyboardEvent} event - default keydown event handler\n\t\t\t\t\t */\n\t\t\t\t\t27: (event) => {\n\t\t\t\t\t\tif (vm.open) {\n\t\t\t\t\t\t\tevent.stopPropagation()\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Default VueSelect's handler\n\t\t\t\t\t\tmap[27](event)\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\n\t\t/**\n\t\t * A unique identifier used to generate IDs and DOM attributes. Must be unique for every instance of the component.\n\t\t *\n\t\t * @see https://vue-select.org/api/props.html#uid\n\t\t */\n\t\tuid: {\n\t\t\ttype: String,\n\t\t\tdefault: () => createElementId(),\n\t\t},\n\n\t\t/**\n\t\t * When `appendToBody` is true, this sets the placement of the dropdown\n\t\t *\n\t\t * @type {'bottom' | 'top'}\n\t\t */\n\t\tplacement: {\n\t\t\ttype: String,\n\t\t\tdefault: 'bottom',\n\t\t},\n\n\t\t/**\n\t\t * If false, the focused dropdown option will not be reset when filtered\n\t\t * options change\n\t\t */\n\t\tresetFocusOnOptionsChange: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Currently selected value\n\t\t *\n\t\t * The `v-model` directive may be used for two-way data binding\n\t\t *\n\t\t * @type {string | number | Record<string | number, any> | Array<any>}\n\t\t *\n\t\t * @see https://vue-select.org/api/props.html#value\n\t\t */\n\t\tmodelValue: {\n\t\t\ttype: [String, Number, Object, Array],\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Enable if a value is required for native form validation\n\t\t */\n\t\trequired: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Any available prop\n\t\t *\n\t\t * @see https://vue-select.org/api/props.html\n\t\t */\n\t\t// Not an actual prop but needed to show in vue-styleguidist docs\n\t\t// eslint-disable-next-line\n\t\t' ': {},\n\t},\n\n\temits: [\n\t\t/**\n\t\t * All events from https://vue-select.org/api/events.html\n\t\t */\n\t\t// Not an actual event but needed to show in vue-styleguidist docs\n\t\t' ',\n\t\t'update:modelValue',\n\t],\n\n\tsetup() {\n\t\tconst clickableArea = Number.parseInt(window.getComputedStyle(document.body).getPropertyValue('--default-clickable-area'))\n\t\tconst gridBaseLine = Number.parseInt(window.getComputedStyle(document.body).getPropertyValue('--default-grid-baseline'))\n\t\tconst avatarSize = clickableArea - 2 * gridBaseLine\n\n\t\treturn {\n\t\t\tavatarSize,\n\t\t\tisLegacy,\n\t\t\tmdiAlertCircleOutline,\n\t\t\tmdiCheck,\n\t\t}\n\t},\n\n\tdata() {\n\t\treturn {\n\t\t\tsearch: '',\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tinputRequired() {\n\t\t\tif (!this.required) {\n\t\t\t\treturn null\n\t\t\t}\n\t\t\t// The <input> itself does not have any value so we set the `required` attribute conditionally\n\t\t\treturn this.modelValue === null || (Array.isArray(this.modelValue) && this.modelValue.length === 0)\n\t\t},\n\n\t\tlocalCalculatePosition() {\n\t\t\tif (this.calculatePosition !== null) {\n\t\t\t\treturn this.calculatePosition\n\t\t\t}\n\n\t\t\treturn (dropdownMenu, component, { width }) => {\n\t\t\t\tdropdownMenu.style.width = width\n\n\t\t\t\tconst addClass = {\n\t\t\t\t\tname: 'addClass',\n\t\t\t\t\tfn(/* middlewareArgs */) {\n\t\t\t\t\t\t// `nc-select__dropdown` scopes our menu styles: the menu is\n\t\t\t\t\t\t// teleported to <body>, so it cannot be reached by the\n\t\t\t\t\t\t// `.nc-select` root scope and would otherwise style every\n\t\t\t\t\t\t// vue-select dropdown on the page (cross-version conflicts).\n\t\t\t\t\t\tdropdownMenu.classList.add('vs__dropdown-menu--floating', 'nc-select__dropdown')\n\t\t\t\t\t\treturn {}\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\tconst togglePlacementClass = {\n\t\t\t\t\tname: 'togglePlacementClass',\n\t\t\t\t\tfn({ placement }) {\n\t\t\t\t\t\tcomponent.$el.classList.toggle(\n\t\t\t\t\t\t\t'select--drop-up',\n\t\t\t\t\t\t\tplacement === 'top',\n\t\t\t\t\t\t)\n\t\t\t\t\t\tdropdownMenu.classList.toggle(\n\t\t\t\t\t\t\t'vs__dropdown-menu--floating-placement-top',\n\t\t\t\t\t\t\tplacement === 'top',\n\t\t\t\t\t\t)\n\t\t\t\t\t\treturn {}\n\t\t\t\t\t},\n\t\t\t\t}\n\n\t\t\t\tconst updatePosition = () => {\n\t\t\t\t\tcomputePosition(component.$refs.toggle, dropdownMenu, {\n\t\t\t\t\t\tplacement: this.placement,\n\t\t\t\t\t\tmiddleware: [\n\t\t\t\t\t\t\t// Flip first so the placement-dependent middleware below see the final placement\n\t\t\t\t\t\t\tflip(),\n\t\t\t\t\t\t\taddClass,\n\t\t\t\t\t\t\ttogglePlacementClass,\n\t\t\t\t\t\t\t// On top placement, leave a gap for the floating label overhang\n\t\t\t\t\t\t\t// (about half the floated label line-height) instead of connecting seamlessly\n\t\t\t\t\t\t\toffset(({ placement }) => (placement.startsWith('top') ? 10 : -1)),\n\t\t\t\t\t\t\tshift({ limiter: limitShift() }),\n\t\t\t\t\t\t],\n\t\t\t\t\t}).then(({ x, y }) => {\n\t\t\t\t\t\tObject.assign(dropdownMenu.style, {\n\t\t\t\t\t\t\tleft: `${x}px`,\n\t\t\t\t\t\t\ttop: `${y}px`,\n\t\t\t\t\t\t\twidth: `${component.$refs.toggle.getBoundingClientRect().width}px`,\n\t\t\t\t\t\t})\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\tconst cleanup = autoUpdate(\n\t\t\t\t\tcomponent.$refs.toggle,\n\t\t\t\t\tdropdownMenu,\n\t\t\t\t\tupdatePosition,\n\t\t\t\t)\n\n\t\t\t\treturn cleanup\n\t\t\t}\n\t\t},\n\n\t\tlocalFilterBy() {\n\t\t\treturn this.filterBy ?? VueSelect.props.filterBy.default\n\t\t},\n\n\t\tlocalLabel() {\n\t\t\treturn this.label ?? VueSelect.props.label.default\n\t\t},\n\n\t\tpropsToForward() {\n\t\t\tconst vueSelectKeys = [\n\t\t\t\t...Object.keys(VueSelect.props),\n\t\t\t\t...VueSelect.mixins.flatMap((mixin) => Object.keys(mixin.props ?? {})),\n\t\t\t]\n\t\t\tconst initialPropsToForward = Object.fromEntries(Object.entries(this.$props)\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unused-vars\n\t\t\t\t.filter(([key, _value]) => vueSelectKeys.includes(key)))\n\t\t\tconst propsToForward = {\n\t\t\t\t...initialPropsToForward,\n\t\t\t\t// Custom overrides of vue-select props\n\t\t\t\tcalculatePosition: this.localCalculatePosition,\n\t\t\t\tcloseOnSelect: !this.keepOpen,\n\t\t\t\tfilterBy: this.localFilterBy,\n\t\t\t\tlabel: this.localLabel,\n\t\t\t}\n\t\t\treturn propsToForward\n\t\t},\n\t},\n\n\tmounted() {\n\t\tif (!this.labelOutside && !this.inputLabel && !this.ariaLabelCombobox) {\n\t\t\twarn('[NcSelect] An `inputLabel` or `ariaLabelCombobox` should be set. If an external label is used, `labelOutside` should be set to `true`.')\n\t\t}\n\t\tif (this.inputLabel && this.ariaLabelCombobox) {\n\t\t\twarn('[NcSelect] Only one of `inputLabel` or `ariaLabelCombobox` should to be set.')\n\t\t}\n\t},\n\n\tmethods: {\n\t\tt,\n\n\t\t/**\n\t\t * Consumer-provided slots forwarded to vue-select, excluding `footer`\n\t\t * which we render ourselves to host the helper text.\n\t\t *\n\t\t * `$slots` is not reactive, so this is a method (re-evaluated on every\n\t\t * render) rather than a computed, to keep the forwarded slot list fresh.\n\t\t *\n\t\t * @return {string[]}\n\t\t */\n\t\tforwardedSlots() {\n\t\t\treturn Object.keys(this.$slots).filter((name) => name !== 'footer')\n\t\t},\n\t},\n}\n</script>\n\n<style lang=\"scss\">\n@use '../../assets/input-border.scss' as border;\n\n// Helper text beneath the control, matching NcInputField's helper text.\n.nc-select.v-select.select .select__helper-text {\n\tdisplay: flex;\n\talign-items: center;\n\tmargin: 0;\n\tpadding-block: 4px;\n\tpadding-inline: var(--border-radius-element);\n\tcolor: var(--color-text-maxcontrast);\n\tfont-size: var(--default-font-size);\n\toverflow-wrap: anywhere;\n\n\t&--error {\n\t\tcolor: var(--color-text-error);\n\t}\n\n\t&--success {\n\t\tcolor: var(--color-text-success);\n\t}\n\n\t.select__helper-text-icon {\n\t\tmargin-inline-end: 8px;\n\t}\n}\n\n/* Custom vue-select CSS variables scoped to NcSelect */\n/* The select's dropdown may be mounted outside the select. */\n/* Therefore, it does not inherit the variables and requires them on its own */\n.nc-select.v-select.select,\n.nc-select__dropdown.vs__dropdown-menu {\n\t/* Search Input */\n\t--vs-search-input-color: var(--color-main-text);\n\t--vs-search-input-bg: var(--color-main-background);\n\t--vs-search-input-placeholder-color: var(--color-text-maxcontrast);\n\n\t/* Font */\n\t--vs-font-size: var(--default-font-size);\n\t--vs-line-height: var(--default-line-height);\n\n\t/* Disabled State */\n\t--vs-state-disabled-bg: var(--color-background-hover);\n\t--vs-state-disabled-color: var(--color-text-maxcontrast);\n\t--vs-state-disabled-controls-color: var(--color-text-maxcontrast);\n\t--vs-state-disabled-cursor: not-allowed;\n\t--vs-disabled-bg: var(--color-background-hover);\n\t--vs-disabled-color: var(--color-text-maxcontrast);\n\t--vs-disabled-cursor: not-allowed;\n\n\t/* Borders */\n\t--vs-border-color: var(--color-border-maxcontrast);\n\t--vs-border-width: var(--border-width-input, 2px) !important;\n\t--vs-border-style: solid;\n\t--vs-border-radius: var(--border-radius-element);\n\n\t/* Component Controls: Clear, Open Indicator */\n\t--vs-controls-color: var(--color-main-text);\n\n\t/* Selected */\n\t--vs-selected-bg: var(--color-background-hover);\n\t--vs-selected-color: var(--color-main-text);\n\t--vs-selected-border-color: var(--vs-border-color);\n\t--vs-selected-border-style: var(--vs-border-style);\n\t--vs-selected-border-width: var(--vs-border-width);\n\n\t/* Dropdown */\n\t--vs-dropdown-bg: var(--color-main-background);\n\t--vs-dropdown-color: var(--color-main-text);\n\t--vs-dropdown-z-index: 9999;\n\t--vs-dropdown-box-shadow: 0px 2px 2px 0px var(--color-box-shadow);\n\n\t/* Options */\n\t--vs-dropdown-option-padding: 8px 20px;\n\n\t/* Active State */\n\t--vs-dropdown-option--active-bg: var(--color-background-hover);\n\t--vs-dropdown-option--active-color: var(--color-main-text);\n\n\t/* Keyboard Focus State */\n\t--vs-dropdown-option--kb-focus-box-shadow: inset 0px 0px 0px 2px var(--vs-border-color);\n\n\t/* Deselect State */\n\t--vs-dropdown-option--deselect-bg: var(--color-error);\n\t--vs-dropdown-option--deselect-color: #fff;\n\n\t/* Transitions */\n\t--vs-transition-duration: 0ms;\n\n\t/* Actions */\n\t--vs-actions-padding: 0 8px 0 8px;\n}\n\n.nc-select.v-select.select {\n\t/* Override default vue-select styles */\n\tmin-height: calc(var(--default-clickable-area) - 2 * var(--border-width-input, 2px));\n\tmin-width: 260px;\n\t// 6px block-start reserves space for the floated label, matching\n\t// NcInputField (.input-field margin-block-start) so fields line up in a row.\n\tmargin: 6px 0 var(--default-grid-baseline);\n\n\t&.vs--open {\n\t\t--vs-border-width: var(--border-width-input-focused, 2px);\n\t}\n\n\t.vs__selected {\n\t\t// min-height (not height) so multi-line entries like NcSelectUsers chips can grow\n\t\tmin-height: calc(var(--default-clickable-area) - 2 * var(--vs-border-width) - var(--default-grid-baseline));\n\t\tmin-width: 0;\n\t\tmax-width: 100%;\n\t\tmargin: calc(var(--default-grid-baseline) / 2);\n\t\tpadding-block: 0;\n\t\tpadding-inline: 12px 8px;\n\t\tborder-radius: 16px !important;\n\t\tbackground: var(--color-primary-element-light);\n\t\tborder: none;\n\t}\n\n\t.vs__search {\n\t\t// NcTextField filling the search area; padding-end reserved for the actions overlay\n\t\twidth: 100%;\n\t\t--input-padding-end: calc(var(--default-clickable-area) + var(--default-grid-baseline));\n\n\t\t// Neutralize vue-select defaults on the wrapper div (no longer the native input).\n\t\t// The height reset also beats legacy global styles (e.g. bundled by the server)\n\t\t// that force a fixed height on `.vs__search` from the old native-input design.\n\t\tborder: none !important;\n\t\tmargin: 0 !important;\n\t\tpadding: 0 !important;\n\t\theight: auto !important;\n\t}\n\n\t// Force floating label when a value is selected (search input is empty but a value exists)\n\t.vs__selected-options:has(.vs__selected) .vs__search {\n\t\t.input-field__input + .input-field__label {\n\t\t\t--input-label-font-size: var(--font-size-small, 13px);\n\t\t\tline-height: 1.5;\n\t\t\tinset-block-start: calc(-1.5 * var(--input-label-font-size) / 2);\n\t\t\tfont-weight: 500;\n\t\t\tborder-radius: var(--default-grid-baseline) var(--default-grid-baseline) 0 0;\n\t\t\tbackground-color: var(--color-main-background);\n\t\t\tpadding-inline: var(--default-grid-baseline);\n\t\t\tmargin-inline: calc(var(--input-padding-start) - var(--default-grid-baseline)) calc(var(--input-padding-end) - var(--default-grid-baseline));\n\t\t\ttransition: height var(--animation-quick), inset-block-start var(--animation-quick), font-size var(--animation-quick), color var(--animation-quick);\n\t\t}\n\t}\n\n\t// Single mode: border is on NcTextField, dropdown-toggle is invisible\n\t&:not(.vs--multiple) .vs__dropdown-toggle {\n\t\tpadding: 0;\n\t\toverflow: visible;\n\t\tborder: none !important;\n\t\tbox-shadow: none !important;\n\t\tbackground: transparent;\n\t}\n\n\t// Anchor the absolutely-positioned actions to the control itself, so content\n\t// rendered below it inside .v-select (e.g. the helper text) does not shift\n\t// the caret's vertical centering.\n\t.vs__dropdown-toggle {\n\t\tposition: relative;\n\t}\n\n\t.vs__actions {\n\t\tposition: absolute;\n\t\tz-index: 999;\n\t\tinset-inline-end: 0;\n\t\ttop: 50%;\n\t\ttransform: translateY(-50%);\n\t\theight: 100%;\n\t\tmargin-block-start: 1px;\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t}\n\n\t.vs__clear {\n\t\tmargin-inline-end: 2px;\n\t}\n\n\t&.vs--open {\n\t\t// Remove bottom border-radius when dropdown is open\n\t\t.vs__search .input-field__input {\n\t\t\tborder-end-start-radius: 0 !important;\n\t\t\tborder-end-end-radius: 0 !important;\n\t\t}\n\t}\n\n\t&.vs--disabled {\n\t\t// Override vue-select's disabled background on all internal elements\n\t\t// to prevent stacking with NcInputField's own background\n\t\t.vs__clear,\n\t\t.vs__dropdown-toggle,\n\t\t.vs__open-indicator,\n\t\t.vs__open-indicator-button,\n\t\t.vs__search,\n\t\t.vs__selected {\n\t\t\tbackground-color: transparent;\n\t\t\tcolor: var(--color-text-maxcontrast);\n\t\t}\n\n\t\t// Lighter border in disabled state to match single mode (NcInputField uses --color-border-dark)\n\t\t.vs__dropdown-toggle {\n\t\t\t--input-border-box-shadow-light: 0 -1px var(--color-border-dark),\n\t\t\t\t0 0 0 1px color-mix(in srgb, var(--color-border-dark), 65% transparent);\n\t\t\t--input-border-box-shadow-dark: 0 1px var(--color-border-dark),\n\t\t\t\t0 0 0 1px color-mix(in srgb, var(--color-border-dark), 65% transparent);\n\t\t}\n\n\t\t.vs__clear,\n\t\t.vs__deselect {\n\t\t\tdisplay: none;\n\t\t}\n\t}\n\n\t&--no-wrap {\n\t\t.vs__dropdown-toggle {\n\t\t\toverflow: hidden;\n\t\t}\n\t\t.vs__selected-options {\n\t\t\tflex-wrap: nowrap;\n\t\t\toverflow: auto !important;\n\t\t\tmin-width: unset;\n\t\t\t.vs__selected {\n\t\t\t\tmin-width: unset;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Drop-up: the menu is detached above the select (calculatePosition leaves a\n\t// gap for the floating label, which stays in its usual top position),\n\t// so keep the regular fully-rounded borders instead of flattening the seam\n\t&--drop-up {\n\t\t&.vs--open {\n\t\t\t.vs__search .input-field__input {\n\t\t\t\tborder-end-start-radius: var(--border-radius-element) !important;\n\t\t\t\tborder-end-end-radius: var(--border-radius-element) !important;\n\t\t\t}\n\n\t\t\t// !important to beat the later-defined down-state open rule\n\t\t\t// (.vs--multiple.vs--open .vs__dropdown-toggle) of equal specificity\n\t\t\t&.vs--multiple .vs__dropdown-toggle {\n\t\t\t\tborder-end-start-radius: var(--border-radius-element) !important;\n\t\t\t\tborder-end-end-radius: var(--border-radius-element) !important;\n\t\t\t\t// Bottom is a regular outer edge here, not a divider seam\n\t\t\t\tborder-block-end-color: var(--color-main-text) !important;\n\t\t\t}\n\t\t}\n\t}\n\n\t.vs__selected-options {\n\t\t// If search is hidden, ensure that the height of the search is the same\n\t\tmin-height: unset;\n\n\t\t// Hide search from dom if unused to prevent unneeded flex wrap\n\t\t.vs__selected ~ .vs__search:has(.input-field__input[readonly]) {\n\t\t\tposition: absolute;\n\t\t}\n\t\tpadding: 0;\n\t\tborder: none;\n\t\toverflow: visible;\n\t}\n\n\t// Multi-select: border on dropdown-toggle (contains tags + input)\n\t// NcTextField is transparent; floating label via #header slot\n\t&.vs--multiple {\n\t\t// The multiple variant otherwise renders ~2px wider than the single one\n\t\t// and overflows its container; inset it by 1px on each side to align.\n\t\tmargin-inline: 1px;\n\n\t\t.vs__dropdown-toggle {\n\t\t\t// Use transparent border in closed state to reserve the same space\n\t\t\t// as the open state's real border, prevents layout jump on click\n\t\t\tborder: var(--border-width-input-focused, 2px) solid transparent;\n\t\t\tbox-shadow: var(--input-border-box-shadow);\n\t\t\t// Top padding for floating label clearance, no bottom padding\n\t\t\tpadding-block: calc(var(--default-grid-baseline) * 1.5) 0;\n\t\t\t// Left padding so tags don't overlap the border-radius curve,\n\t\t\t// right padding reserved for the actions overlay (chevron)\n\t\t\tpadding-inline: var(--default-grid-baseline) calc(var(--default-clickable-area) + var(--default-grid-baseline));\n\t\t\toverflow: visible;\n\t\t\tbackground: var(--color-main-background);\n\t\t}\n\n\t\t// Wider reservation when the clear button is shown next to the chevron\n\t\t&:has(.vs__clear) .vs__dropdown-toggle {\n\t\t\tpadding-inline-end: calc(2 * var(--default-clickable-area));\n\t\t}\n\n\t\t// When open, switch to visible border with subtle bottom divider\n\t\t&.vs--open .vs__dropdown-toggle {\n\t\t\tbox-shadow: none !important;\n\t\t\tborder-color: var(--color-main-text);\n\t\t\t// Subtle divider line between tags and dropdown (not fully transparent)\n\t\t\tborder-block-end-color: var(--color-border-maxcontrast);\n\t\t\tborder-end-start-radius: 0;\n\t\t\tborder-end-end-radius: 0;\n\t\t\toutline: 2px solid var(--color-main-background);\n\t\t}\n\n\t\t// Remove NcTextField border in multi mode, border is on dropdown-toggle\n\t\t.vs__search .input-field__input {\n\t\t\tbox-shadow: none !important;\n\t\t\tbackground: transparent;\n\t\t}\n\n\t\t// NcTextField shares flex row with tags, always inline, no absolute hiding.\n\t\t// No min-width: it may shrink fully so it never forces an empty wrap row\n\t\t// (matches vue-select's own search sizing)\n\t\t.vs__search {\n\t\t\twidth: 0;\n\t\t\tflex-grow: 1;\n\t\t\tmin-width: 0;\n\t\t}\n\n\t\t// No-wrap: clip overflow inside the toggle (needs to be here\n\t\t// for specificity to beat the overflow: visible above)\n\t\t&.select--no-wrap {\n\t\t\t.vs__dropdown-toggle {\n\t\t\t\toverflow: hidden;\n\t\t\t}\n\n\t\t\t.vs__actions {\n\t\t\t\t// Slight fade for non-wrap tags display\n\t\t\t\tbackground: linear-gradient(90deg, transparent, var(--color-main-background) 10%, var(--color-main-background) 100%);\n\t\t\t\tmargin-block: 0px;\n\t\t\t\tmargin-inline-end: 2px;\n\t\t\t\tborder-radius: var(--border-radius-element);\n\t\t\t\theight: calc(100% - 6px);\n\t\t\t}\n\t\t}\n\n\t\t// No label margin needed, label is via #header\n\t\t.vs__search .input-field {\n\t\t\tmargin-block-start: 0;\n\t\t}\n\n\t\t// Match NcTextField height to tag row height for consistent toggle sizing\n\t\t.vs__search .input-field__main-wrapper {\n\t\t\theight: calc(var(--default-clickable-area) - 2 * var(--vs-border-width) - var(--default-grid-baseline));\n\t\t\tmargin: calc(var(--default-grid-baseline) / 2) 0;\n\t\t}\n\n\t\t// Label: centered inside toggle when empty (placeholder-like),\n\t\t// floats above border when has value or open (matches NcInputField)\n\t\t.select__label {\n\t\t\tposition: absolute;\n\t\t\tz-index: 1;\n\t\t\tinset-inline-start: var(--border-width-input-focused, 2px);\n\t\t\t// Center vertically regardless of toggle height\n\t\t\ttop: 50%;\n\t\t\ttransform: translateY(-50%);\n\t\t\tfont-size: var(--default-font-size);\n\t\t\tmargin-inline: var(--border-radius-element);\n\t\t\tcolor: var(--color-text-maxcontrast);\n\t\t\tpointer-events: none;\n\t\t\twhite-space: nowrap;\n\t\t\toverflow: hidden;\n\t\t\ttext-overflow: ellipsis;\n\t\t\tmax-width: calc(100% - var(--clickable-area-large));\n\t\t\ttransition: top var(--animation-quick), transform var(--animation-quick), font-size var(--animation-quick), font-weight var(--animation-quick), background-color var(--animation-quick) var(--animation-slow);\n\t\t}\n\n\t\t// Float label when has tags or dropdown is open\n\t\t&:has(.vs__selected) .select__label,\n\t\t&.vs--open .select__label {\n\t\t\t--input-label-font-size: var(--font-size-small, 13px);\n\t\t\tfont-size: var(--input-label-font-size);\n\t\t\tline-height: 1.5;\n\t\t\t// Match NcInputField: half the line-height above the border\n\t\t\ttop: calc(-1.5 * var(--input-label-font-size) / 2);\n\t\t\ttransform: none;\n\t\t\tfont-weight: 500;\n\t\t\tborder-radius: var(--default-grid-baseline) var(--default-grid-baseline) 0 0;\n\t\t\tbackground-color: var(--color-main-background);\n\t\t\tpadding-inline: var(--default-grid-baseline);\n\t\t\tmargin-inline: calc(var(--border-radius-element) - var(--default-grid-baseline));\n\t\t\ttransition: top var(--animation-quick), transform var(--animation-quick), font-size var(--animation-quick), font-weight var(--animation-quick), background-color var(--animation-quick);\n\t\t}\n\t}\n\n\t&.vs--single {\n\t\t// In single mode, overlay the selected value on top of the NcTextField input area\n\t\t// so it appears inside the border (which is on the NcTextField, not the toggle)\n\t\t.vs__selected-options {\n\t\t\tposition: relative;\n\t\t\tflex-wrap: nowrap;\n\t\t\t// Ensure height even when search input is hidden (vs--unsearchable)\n\t\t\tmin-height: var(--default-clickable-area);\n\t\t}\n\n\t\t.vs__selected {\n\t\t\tposition: absolute;\n\t\t\t// Skip the label clearance so the overlay covers only the input box,\n\t\t\t// keeping (multi-line) content like NcSelectUsers centered on the input\n\t\t\t// (6px = NcInputField .input-field margin-block-start)\n\t\t\tinset-block: 6px 0;\n\t\t\tinset-inline-start: 0;\n\t\t\tinset-inline-end: 0;\n\t\t\tmargin: 0;\n\t\t\tz-index: 2; // above vs__search (z-index: 1 from vue-select default)\n\t\t\tpointer-events: none;\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tpadding-block: 0;\n\t\t\t// Match the input text position: main-wrapper padding (border width) + input padding\n\t\t\tpadding-inline: calc(var(--border-radius-element) + var(--border-width-input-focused, 2px)) var(--input-padding-end, calc(var(--default-clickable-area) + var(--default-grid-baseline)));\n\t\t\tbackground: unset !important;\n\t\t\tborder: none;\n\t\t\tborder-radius: 0;\n\t\t\theight: unset;\n\t\t\tmin-height: unset;\n\t\t\tfont-size: var(--default-font-size);\n\t\t\tcolor: var(--color-main-text);\n\t\t\twhite-space: nowrap;\n\t\t\toverflow: hidden;\n\t\t\ttext-overflow: ellipsis;\n\t\t}\n\n\t\t// No label clearance to skip when the label is external\n\t\t&:has(.input-field--label-outside) .vs__selected {\n\t\t\tinset-block-start: 0;\n\t\t}\n\n\t\t// Extra padding when clear button visible (clear + chevron need more space)\n\t\t&:has(.vs__clear) .vs__selected {\n\t\t\tpadding-inline-end: calc(2 * var(--default-clickable-area));\n\t\t}\n\n\t\t&.vs--loading,\n\t\t&.vs--open {\n\t\t\t.vs__selected {\n\t\t\t\t// Fix color to be accessible while typing\n\t\t\t\topacity: 0.4;\n\t\t\t}\n\t\t}\n\n\t\t// Hide the selected value as soon as the user types a query\n\t\t// (restores vue-select's default, overridden by our display: flex above)\n\t\t&.vs--searching .vs__selected {\n\t\t\tdisplay: none;\n\t\t}\n\t}\n}\n\n// Dropdown menu is teleported to <body>, so it can't live under the\n// `.nc-select` root scope. The `.nc-select__dropdown` class (added in\n// calculatePosition) scopes it instead, so these styles and CSS variables\n// only affect our menus and never leak to other vue-select instances.\n.nc-select__dropdown.vs__dropdown-menu {\n\tborder-width: var(--border-width-input-focused) !important;\n\tborder-color: var(--color-main-text) !important;\n\toutline: none !important;\n\tbox-shadow:\n\t\t-2px 0 0 var(--color-main-background), // Right\n\t\t0 2px 0 var(--color-main-background), // Bottom\n\t\t2px 0 0 var(--color-main-background), // Left\n\t\t!important;\n\tpadding: 4px !important;\n\n\t&--floating {\n\t\t/* Fallback styles overidden by programmatically set inline styles */\n\t\twidth: max-content;\n\t\tposition: absolute;\n\t\ttop: 0;\n\t\tinset-inline-start: 0;\n\n\t\t// Top placement: the menu is detached from the select (gap for the\n\t\t// floating label), so it keeps a full border on all sides\n\t\t&-placement-top {\n\t\t\tborder-radius: var(--vs-border-radius) !important;\n\t\t\tborder-top-style: var(--vs-border-style) !important;\n\t\t\tbox-shadow:\n\t\t\t\t0 -2px 0 var(--color-main-background), // Top\n\t\t\t\t-2px 0 0 var(--color-main-background), // Right\n\t\t\t\t0 2px 0 var(--color-main-background), // Bottom\n\t\t\t\t2px 0 0 var(--color-main-background), // Left\n\t\t\t\t!important\n\t\t}\n\t}\n\n\t.vs__dropdown-option {\n\t\tborder-radius: 6px !important;\n\t}\n\n\t.vs__no-options {\n\t\tcolor: var(--color-text-maxcontrast) !important;\n\t}\n}\n\n// Border for .vs__dropdown-toggle, inlined from inputLikeBorder mixin\n// because the mixin's @media #{&} produces doubled selectors when nested.\n.nc-select.v-select.select .vs__dropdown-toggle {\n\t--input-border-box-shadow-light: 0 -1px var(--vs-border-color),\n\t\t0 0 0 1px color-mix(in srgb, var(--vs-border-color), 65% transparent);\n\t--input-border-box-shadow-dark: 0 -1px var(--vs-border-color),\n\t\t0 0 0 1px color-mix(in srgb, var(--vs-border-color), 65% transparent);\n\t--input-border-box-shadow: var(--input-border-box-shadow-light);\n\tborder: none;\n\tborder-radius: var(--border-radius-element);\n\tbox-shadow: var(--input-border-box-shadow);\n}\n\n// Hover: use .vs--disabled on parent (toggle div never has [disabled] attribute)\n.nc-select.v-select.select:not(.vs--disabled) .vs__dropdown-toggle:hover {\n\tbox-shadow: 0 0 0 1px var(--vs-border-color);\n}\n\n@media (prefers-color-scheme: dark) {\n\t.nc-select.v-select.select .vs__dropdown-toggle {\n\t\t--input-border-box-shadow: var(--input-border-box-shadow-dark);\n\t}\n}\n\n[data-theme-dark] .nc-select.v-select.select .vs__dropdown-toggle {\n\t--input-border-box-shadow: var(--input-border-box-shadow-dark);\n}\n\n[data-theme-light] .nc-select.v-select.select .vs__dropdown-toggle {\n\t--input-border-box-shadow: var(--input-border-box-shadow-light);\n}\n\n.select--legacy.nc-select.v-select.select .vs__dropdown-toggle {\n\tbox-shadow: 0 0 0 1px var(--vs-border-color);\n\n\t&:hover:not([disabled]) {\n\t\tbox-shadow: 0 0 0 2px var(--vs-border-color);\n\t}\n}\n</style>\n"],"names":["NcTextField","Close","_openBlock","_createBlock","_mergeProps","_withCtx","_createVNode","_normalizeClass","_renderSlot","_normalizeProps","_guardReactiveProps","_createElementVNode","_createElementBlock","_createTextVNode","_renderList"],"mappings":"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"}
|
|
@@ -245,12 +245,12 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
245
245
|
};
|
|
246
246
|
}
|
|
247
247
|
});
|
|
248
|
-
const uploadPicker_progress = "
|
|
249
|
-
const uploadPicker_progress__uploading = "
|
|
250
|
-
const uploadPicker_progress__paused = "
|
|
251
|
-
const breathing = "
|
|
252
|
-
const uploadPicker_progressLabel = "
|
|
253
|
-
const uploadPicker_progressLabelSpeed = "
|
|
248
|
+
const uploadPicker_progress = "_uploadPicker_progress_nucBV";
|
|
249
|
+
const uploadPicker_progress__uploading = "_uploadPicker_progress__uploading_i-lP3";
|
|
250
|
+
const uploadPicker_progress__paused = "_uploadPicker_progress__paused_x9K9W";
|
|
251
|
+
const breathing = "_breathing_cXpss";
|
|
252
|
+
const uploadPicker_progressLabel = "_uploadPicker_progressLabel_1DNU0";
|
|
253
|
+
const uploadPicker_progressLabelSpeed = "_uploadPicker_progressLabelSpeed_YtMHl";
|
|
254
254
|
const style0 = {
|
|
255
255
|
uploadPicker_progress,
|
|
256
256
|
uploadPicker_progress__uploading,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NcUploadPicker.mjs","sources":["../../node_modules/@nextcloud/paths/dist/index.mjs","../../src/components/NcUploadPicker/NcUploadPicker.vue"],"sourcesContent":["function encodePath(path) {\n if (!path) {\n return path;\n }\n return path.split(\"/\").map(encodeURIComponent).join(\"/\");\n}\nfunction basename(path, extname2) {\n path = path.replace(/\\\\/g, \"/\").replace(/\\/+$/g, \"\").replace(/.*\\//, \"\");\n if (extname2 && extname2 !== path && path.endsWith(extname2)) {\n return path.substring(0, path.length - extname2.length);\n }\n return path;\n}\nfunction dirname(path) {\n path = path.replaceAll(/\\\\/g, \"/\");\n const sections = path.split(\"/\");\n if (sections.length <= 1) {\n return \".\";\n }\n sections.pop();\n if (sections.length === 1 && sections[0] === \"\") {\n return \"/\";\n }\n return sections.join(\"/\");\n}\nfunction extname(path) {\n const base = basename(path);\n const index = base.lastIndexOf(\".\");\n if (index > 0) {\n return base.substring(index);\n }\n return \"\";\n}\nfunction join(...args) {\n if (arguments.length < 1) {\n return \"\";\n }\n const nonEmptyArgs = args.filter((arg) => arg.length > 0);\n if (nonEmptyArgs.length < 1) {\n return \"\";\n }\n const lastArg = nonEmptyArgs[nonEmptyArgs.length - 1];\n const leadingSlash = nonEmptyArgs[0].charAt(0) === \"/\";\n const trailingSlash = lastArg.charAt(lastArg.length - 1) === \"/\";\n const sections = nonEmptyArgs.reduce((acc, section) => acc.concat(section.split(\"/\")), []);\n let first = !leadingSlash;\n const path = sections.reduce((acc, section) => {\n if (section === \"\") {\n return acc;\n }\n if (first) {\n first = false;\n return acc + section;\n }\n return acc + \"/\" + section;\n }, \"\");\n if (trailingSlash) {\n return path + \"/\";\n }\n return path;\n}\nfunction isSamePath(path1, path2) {\n const pathSections1 = (path1 || \"\").split(\"/\").filter((p) => p !== \".\");\n const pathSections2 = (path2 || \"\").split(\"/\").filter((p) => p !== \".\");\n path1 = join(...pathSections1);\n path2 = join(...pathSections2);\n return path1 === path2;\n}\nfunction normalize(path) {\n const sections = path.split(\"/\").filter((p, index, arr) => p !== \"\" || index === 0 || index === arr.length - 1).filter((p) => p !== \".\");\n const sanitizedSections = [];\n for (const section of sections) {\n const lastSection = sanitizedSections.at(-1);\n if (section === \"..\" && lastSection !== \"..\") {\n if (lastSection === void 0) {\n sanitizedSections.push(section);\n } else if (lastSection !== \"\") {\n sanitizedSections.pop();\n }\n } else {\n sanitizedSections.push(section);\n }\n }\n return sanitizedSections.join(\"/\");\n}\nexport {\n basename,\n dirname,\n encodePath,\n extname,\n isSamePath,\n join,\n normalize\n};\n//# sourceMappingURL=index.mjs.map\n","<!--\n - SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<script setup lang=\"ts\">\nimport type { Folder, IFolder, INode } from '@nextcloud/files'\nimport type { IUpload } from '@nextcloud/files/upload'\nimport type { FilePickerItem, FilePickerItemGroup } from '../NcFilePicker/NcFilePicker.vue'\n\nimport { mdiClose, mdiPlus } from '@mdi/js'\nimport { openConflictPicker } from '@nextcloud/dialogs'\nimport { getUniqueName } from '@nextcloud/files'\nimport { getUploader, UploaderStatus, UploadStatus } from '@nextcloud/files/upload'\nimport { basename } from '@nextcloud/paths'\nimport { computed, onBeforeMount, onUnmounted, ref, useTemplateRef, watch } from 'vue'\nimport NcButton from '../NcButton/NcButton.vue'\nimport NcFilePicker from '../NcFilePicker/NcFilePicker.vue'\nimport NcIconSvgWrapper from '../NcIconSvgWrapper/NcIconSvgWrapper.vue'\nimport NcProgressBar from '../NcProgressBar/NcProgressBar.vue'\nimport { useFormatRelativeTime } from '../../composables/index.ts'\nimport { t } from '../../l10n.ts'\nimport { createElementId } from '../../utils/createElementId.ts'\nimport { logger } from '../../utils/logger.ts'\n\nconst props = withDefaults(defineProps<{\n\t/**\n\t * Actions to be shown in the upload picker menu.\n\t */\n\tactions?: FilePickerItem[] | FilePickerItemGroup[]\n\n\t/**\n\t * The upload destination folder\n\t */\n\tdestination: IFolder\n\n\t/**\n\t * A callback function to get the list of files present in the destination folder.\n\t */\n\tcontent: (relativePath?: string) => Promise<INode[]>\n\n\t/**\n\t * Allowed MIME types to upload\n\t */\n\taccept?: string[]\n\n\t/**\n\t * Disable the upload picker\n\t */\n\tdisabled?: boolean\n\n\t/**\n\t * The label of the upload picker button\n\t */\n\tlabel?: string\n\n\t/**\n\t * Allow uploading multiple files\n\t */\n\tmultiple?: boolean\n\n\t/**\n\t * Only show the icon without text label\n\t */\n\ticonOnly?: boolean\n\n\t/**\n\t * The variant of the menu button\n\t */\n\tvariant?: 'primary' | 'secondary' | 'tertiary'\n\n\t/**\n\t * Allow uploading directories\n\t */\n\tdirectory?: boolean\n}>(), {\n\tactions: () => [],\n\taccept: () => [],\n\tlabel: () => t('New'),\n\tvariant: 'secondary',\n})\n\nconst emit = defineEmits<{\n\t/**\n\t * Emitted when an upload has started.\n\t */\n\t'upload:started': [upload: IUpload]\n\t/**\n\t * Emitted when an upload has finished successfully.\n\t */\n\t'upload:finished': [upload: IUpload]\n\t/**\n\t * The queue has been paused, and no more uploads will be processed until resumed.\n\t */\n\tpaused: [queue: IUpload[]]\n\t/**\n\t * The queue has resumed uploading after being paused.\n\t */\n\tresumed: [queue: IUpload[]]\n\t/**\n\t * The queue has finished uploading all files.\n\t */\n\tfinished: []\n}>()\n\ndefineExpose({\n\treset,\n})\n\nconst filePickerElement = useTemplateRef('filePicker')\nconst progressTimeId = createElementId()\n\nconst uploadManager = getUploader()\nonBeforeMount(() => {\n\twindow.addEventListener('beforeunload', onBeforePageUnload)\n\tuploadManager.addEventListener('uploadFinished', onUploadFinished)\n\tuploadManager.addEventListener('uploadStarted', onUploadStarted)\n\tuploadManager.addEventListener('uploadProgress', updateEta)\n\tuploadManager.addEventListener('finished', onUploaderFinished)\n\tuploadManager.addEventListener('paused', onUploaderPaused)\n\tuploadManager.addEventListener('reset', updateUploadStatus)\n\tuploadManager.addEventListener('resumed', onUploaderResumed)\n\tupdateUploadStatus()\n})\nonUnmounted(() => {\n\twindow.removeEventListener('beforeunload', onBeforePageUnload)\n\tuploadManager.removeEventListener('uploadFinished', onUploadFinished)\n\tuploadManager.removeEventListener('uploadStarted', onUploadStarted)\n\tuploadManager.removeEventListener('uploadProgress', updateEta)\n\tuploadManager.removeEventListener('finished', onUploaderFinished)\n\tuploadManager.removeEventListener('paused', onUploaderPaused)\n\tuploadManager.removeEventListener('reset', updateUploadStatus)\n\tuploadManager.removeEventListener('resumed', onUploaderResumed)\n})\n\nwatch(() => props.destination, () => setDestination(props.destination), { immediate: true })\n\nconst isPaused = ref(uploadManager.status === UploaderStatus.PAUSED)\n/** Handle uploader paused event */\nfunction onUploaderPaused() {\n\tupdateUploadStatus()\n\temit('paused', [...uploadManager.queue])\n}\n/** Handle uploader resumed event */\nfunction onUploaderResumed() {\n\tupdateUploadStatus()\n\temit('resumed', [...uploadManager.queue])\n}\n\nconst hasFailure = ref(false)\nconst isUploading = ref(false)\nconst isAssembling = ref(false)\nconst isOnlyAssembling = ref(false)\n\n/**\n * Update the upload status flags based on the current queue\n */\nfunction updateUploadStatus() {\n\tisPaused.value = uploadManager.status === UploaderStatus.PAUSED\n\t// While paused the queue is not processed, but the queued uploads are still pending\n\tisUploading.value = uploadManager.status === UploaderStatus.UPLOADING\n\t\t|| (isPaused.value && uploadManager.queue.length > 0)\n\thasFailure.value = uploadManager.queue.some((upload: IUpload) => upload.status === UploadStatus.FAILED)\n\tisAssembling.value = uploadManager.queue.some((upload: IUpload) => upload.status === UploadStatus.ASSEMBLING)\n\t// only assembling if assembling at all AND all other uploads are already finished (or failed)\n\tisOnlyAssembling.value = isAssembling.value\n\t\t&& uploadManager.queue.every((upload: IUpload) => upload.status >= UploadStatus.ASSEMBLING)\n}\n\n/**\n * Reset the file input form\n */\nfunction reset() {\n\tfilePickerElement.value?.reset()\n}\n\n/**\n * Set the upload destination\n *\n * @param destination - The new upload destination\n */\nfunction setDestination(destination: IFolder) {\n\tif (!destination) {\n\t\tlogger.debug('Invalid destination')\n\t\treturn\n\t}\n\n\tuploadManager.destination = destination as Folder\n}\n\nconst etaProgress = ref(0)\nconst etaSpeed = ref('')\nconst etaRaw = ref<number>(Infinity)\nconst etaTimeRaw = computed(() => etaRaw.value === Infinity ? Infinity : new Date(Date.now() + etaRaw.value))\nconst etaTimeFormatted = useFormatRelativeTime(etaTimeRaw, { ignoreSeconds: true })\nconst etaTime = computed(() => etaTimeRaw.value === Infinity ? t('Estimating …') : etaTimeFormatted.value)\n/** Update the ETA and speed values */\nfunction updateEta() {\n\tetaRaw.value = uploadManager.statistics.eta === Infinity ? Infinity : (uploadManager.statistics.eta * 1000)\n\tetaSpeed.value = uploadManager.statistics.speedReadable\n\tetaProgress.value = uploadManager.statistics.progress\n}\n\n/**\n * Handle uploader finished event\n */\nfunction onUploaderFinished() {\n\tupdateUploadStatus()\n\temit('finished')\n}\n\n/**\n * Handle upload finished event\n *\n * @param event - The upload finished event\n */\nfunction onUploadFinished(event: CustomEvent<IUpload>) {\n\tupdateUploadStatus()\n\temit('upload:finished', event.detail)\n}\n\n/**\n * Handle upload started event\n *\n * @param event - The upload started event\n */\nfunction onUploadStarted(event: CustomEvent<IUpload>) {\n\tupdateUploadStatus()\n\temit('upload:started', event.detail)\n}\n\n/**\n * Start uploading\n *\n * @param files - The files to upload\n */\nasync function onPick(files: File[]) {\n\ttry {\n\t\tawait uploadManager\n\t\t\t.batchUpload('', files, { callback: handleConflicts })\n\t} catch (error) {\n\t\tlogger.debug('Error while uploading', { error })\n\t} finally {\n\t\treset()\n\t}\n}\n\n/**\n * Handle conflicts during upload\n *\n * @param nodes - The nodes that might conflict\n * @param currentPath - The path of the current directory\n */\nasync function handleConflicts(nodes: string[], currentPath: string): Promise<Record<string, string> | false> {\n\ttry {\n\t\tconst content = await props.content(currentPath)\n\t\tconst conflicts = content.filter((node) => nodes.includes(node.displayname) || nodes.includes(node.basename))\n\t\tconst uploadMapping = Object.fromEntries(nodes.map((name) => [name, name]))\n\t\tif (conflicts.length === 0) {\n\t\t\treturn uploadMapping\n\t\t}\n\n\t\t// The conflict picker requires the incoming and the existing nodes to be aligned,\n\t\t// so the existing content has to be filtered to only contain the conflicting nodes.\n\t\tconst existingNodes = content.filter((node) => nodes.includes(node.displayname) || nodes.includes(node.basename))\n\t\t// @ts-expect-error -- conflict between versons of dependencies - needs to be fixed in @nextcloud/dialogs\n\t\tconst result = await openConflictPicker(basename(currentPath), conflicts, existingNodes, { recursive: props.directory })\n\t\tif (result) {\n\t\t\tconst usedNames = content.map((node) => node.basename)\n\t\t\tfor (const node of conflicts) {\n\t\t\t\tif ((result.skipped as unknown as INode[]).some((skipped) => skipped.basename === node.basename)) {\n\t\t\t\t\tdelete uploadMapping[node.basename]\n\t\t\t\t} else if ((result.renamed as unknown as INode[]).some((renamed) => renamed.basename === node.basename)) {\n\t\t\t\t\tconst newName = getUniqueName(basename(node.basename), usedNames)\n\t\t\t\t\tuploadMapping[node.basename] = newName\n\t\t\t\t\tusedNames.push(newName)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn uploadMapping\n\t\t}\n\t} catch (error) {\n\t\tlogger.error('Error during conflict resolution - skipping upload', { error })\n\t}\n\treturn false\n}\n\n/**\n * Cancel ongoing queue\n */\nfunction onCancel() {\n\tuploadManager.reset()\n\treset()\n}\n\n/**\n * Handle page unload.\n * Block the unload if there are ongoing uploads.\n *\n * @param event - The event\n */\nfunction onBeforePageUnload(event: BeforeUnloadEvent) {\n\tif (uploadManager.queue.length > 0) {\n\t\tevent.preventDefault()\n\t\tevent.returnValue = ''\n\t}\n}\n</script>\n\n<template>\n\t<NcFilePicker\n\t\tref=\"filePicker\"\n\t\t:accept\n\t\t:actionCaption=\"actions.length > 0 || directory ? t('Upload from device') : undefined\"\n\t\t:actions\n\t\t:directory\n\t\t:disabled\n\t\t:iconOnly\n\t\t:label\n\t\t:multiple\n\t\t:variant\n\t\t@pick=\"onPick\">\n\t\t<template #icon>\n\t\t\t<NcIconSvgWrapper :path=\"mdiPlus\" />\n\t\t</template>\n\n\t\t<!-- Progressbar and status -->\n\t\t<div\n\t\t\tv-show=\"isUploading\"\n\t\t\t:class=\"[$style.uploadPicker_progress, {\n\t\t\t\t[$style.uploadPicker_progress__uploading]: isUploading,\n\t\t\t\t[$style.uploadPicker_progress__paused]: isPaused,\n\t\t\t}]\">\n\t\t\t<NcProgressBar\n\t\t\t\t:ariaLabel=\"t('Upload progress')\"\n\t\t\t\t:ariaDescribedby=\"progressTimeId\"\n\t\t\t\t:error=\"hasFailure\"\n\t\t\t\t:value=\"etaProgress\"\n\t\t\t\tsize=\"medium\" />\n\t\t\t<p :id=\"progressTimeId\" :class=\"$style.uploadPicker_progressLabel\">\n\t\t\t\t<span v-if=\"isPaused\">\n\t\t\t\t\t{{ t('paused') /* TRANSLATORS: State of the current upload - it is paused */ }}\n\t\t\t\t</span>\n\t\t\t\t<span v-else-if=\"isOnlyAssembling\">\n\t\t\t\t\t{{ t('assembling') /* TRANSLATORS: State of the current upload - chunks of the uploaded files are being assembled into the final file */ }}\n\t\t\t\t</span>\n\t\t\t\t<span v-else :title=\"`${etaTime} (${etaSpeed})`\">\n\t\t\t\t\t{{ etaTime }}\n\t\t\t\t\t<!-- the speed is included in the tooltip / title so we only show it in the text content if there is enough space (not showing \"a few seconds left\") -->\n\t\t\t\t\t<span v-if=\"etaSpeed && etaRaw > 31000\" :class=\"$style.uploadPicker_progressLabelSpeed\">\n\t\t\t\t\t\t({{ etaSpeed }})\n\t\t\t\t\t</span>\n\t\t\t\t</span>\n\t\t\t</p>\n\t\t</div>\n\n\t\t<!-- Cancel upload button -->\n\t\t<NcButton\n\t\t\tv-if=\"isUploading && !isOnlyAssembling\"\n\t\t\t:class=\"$style.uploadPicker_cancelButton\"\n\t\t\t:aria-label=\"t('Cancel uploads')\"\n\t\t\tvariant=\"tertiary\"\n\t\t\t@click=\"onCancel\">\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</NcFilePicker>\n</template>\n\n<style module>\n.uploadPicker_progress {\n\t--upload-picker-progress-width: 200px;\n\twidth: var(--upload-picker-progress-width);\n\t/* Animate show/hide */\n\tmax-width: 0;\n\ttransition: max-width var(--animation-quick) ease-in-out;\n\t/* Align progress/text separation with the middle */\n\tmargin-top: 8px;\n}\n\n.uploadPicker_progress__uploading {\n\tmax-width: var(--upload-picker-progress-width);\n\n\t/* Visually more pleasing spacing */\n\tmargin-inline: 8px 20px;\n}\n\n.uploadPicker_progress__paused {\n\tanimation: breathing 3s ease-out infinite normal;\n}\n\n.uploadPicker_progressLabel {\n\toverflow: hidden;\n\twhite-space: nowrap;\n\ttext-overflow: ellipsis;\n}\n\n.uploadPicker_progressLabelSpeed{\n\tcolor: var(--color-text-maxcontrast);\n}\n\n@keyframes breathing {\n\t0% {\n\t\topacity: .5;\n\t}\n\t25% {\n\t\topacity: 1;\n\t}\n\t60% {\n\t\topacity: .5;\n\t}\n\t100% {\n\t\topacity: .5;\n\t}\n}\n</style>\n\n<docs>\n## Requirements\n\nTo use the `NcUploadPicker` component, you need to install the following packages:\n- `@nextcloud/dialogs`\n- `@nextcloud/files`\n\n## Usage\n\nThe upload picker lets users pick files – or whole directories – from their device and uploads them\nto a folder on the Nextcloud server, using the shared uploader of `@nextcloud/files/upload`.\nWhile uploading it shows the progress, the estimated remaining time and a button to cancel all queued uploads.\n\nTwo props are required to set it up:\n\n- `destination`: The folder to upload into, as an `IFolder` of `@nextcloud/files`.\n- `content`: A callback that resolves with the nodes that already exist in a folder that is uploaded into.\n It is called with the path relative to the `destination` – the empty string for the destination itself –\n and is used to detect upload conflicts. If there are conflicts, the user is asked to skip or rename\n the conflicting files.\n\n### Exposed methods\n\n- `function reset(): void`\n Reset the internal state of the picker, e.g. to clear the current selection.\n\n**Note**: All upload pickers share the global uploader instance of `getUploader()`,\nincluding its queue and its destination. Because of that only a single upload picker\nshould be mounted at a time – in the examples below the picker that was mounted last defines the destination.\n\n**Note about the examples**: There is no Nextcloud server behind the styleguide,\nso the examples use a fake WebDAV server that simulates slow – but always successful – uploads.\nUploading a file called `Photo.jpg` or `Notes.md` triggers the conflict dialog,\nfiles larger than 10 MiB are uploaded in chunks.\n\n### Basic usage\n\n```vue\n<template>\n\t<div>\n\t\t<NcUploadPicker\n\t\t\t:content=\"fetchContent\"\n\t\t\t:destination=\"destination\"\n\t\t\tmultiple\n\t\t\t@finished=\"log('finished')\"\n\t\t\t@upload:finished=\"log('upload:finished', $event)\"\n\t\t\t@upload:started=\"log('upload:started', $event)\" />\n\n\t\t<NcNoteCard v-if=\"events.length === 0\" type=\"info\">\n\t\t\tPick some files to upload them to <code>{{ destination.path }}</code>.\n\t\t</NcNoteCard>\n\t\t<ul v-else>\n\t\t\t<li v-for=\"(event, index) in events\" :key=\"index\">\n\t\t\t\t{{ event }}\n\t\t\t</li>\n\t\t</ul>\n\t</div>\n</template>\n<script>\nimport { File as NcFile, Folder, Permission } from '@nextcloud/files'\nimport { generateRemoteUrl } from '@nextcloud/router'\nimport { ref } from 'vue'\n\n// The folder the picked files are uploaded into\nconst destination = new Folder({\n\tid: 42,\n\towner: 'admin',\n\tpermissions: Permission.ALL,\n\troot: '/files/admin',\n\tsource: generateRemoteUrl('dav/files/admin/Uploads'),\n})\n\n// The nodes that already exist in the destination, in a real app this is the result of a PROPFIND\nconst existingNodes = ['Photo.jpg', 'Notes.md'].map((name) => new NcFile({\n\tmime: 'application/octet-stream',\n\towner: 'admin',\n\troot: '/files/admin',\n\tsource: `${destination.source}/${name}`,\n}))\n\nexport default {\n\tsetup() {\n\t\tconst events = ref([])\n\n\t\treturn {\n\t\t\tdestination,\n\t\t\tevents,\n\n\t\t\t// Provide the content of the folder that is uploaded into to allow detecting conflicts\n\t\t\tasync fetchContent(relativePath) {\n\t\t\t\t// Folders created by the upload itself are empty, so they never conflict\n\t\t\t\treturn relativePath ? [] : existingNodes\n\t\t\t},\n\n\t\t\tlog(name, upload) {\n\t\t\t\t// One `upload:*` event is emitted for the destination itself - shown as `/` - and one per picked file\n\t\t\t\tconst path = upload && decodeURIComponent(upload.source.slice(destination.source.length))\n\t\t\t\tevents.value.unshift(upload ? `${name}: ${path}` : name)\n\t\t\t},\n\t\t}\n\t},\n}\n</script>\n```\n\n### Directories and custom actions\n\nSetting `directory` adds an entry to upload a whole directory tree, which is recreated in the destination.\nAdditional entries – like the \"New folder\" action of the Files app – can be added using the `actions` prop,\neither as a flat list or grouped with a caption.\nThe `accept` prop restricts the file types that can be picked.\n\n```vue\n<template>\n\t<div>\n\t\t<NcUploadPicker\n\t\t\t:accept=\"['image/jpeg', 'image/png']\"\n\t\t\t:actions=\"actions\"\n\t\t\t:content=\"fetchContent\"\n\t\t\t:destination=\"destination\"\n\t\t\tdirectory\n\t\t\tlabel=\"Add media\"\n\t\t\tmultiple\n\t\t\tvariant=\"primary\" />\n\n\t\t<NcNoteCard v-if=\"lastAction\" type=\"success\">\n\t\t\t{{ lastAction }}\n\t\t</NcNoteCard>\n\t</div>\n</template>\n<script>\nimport svgFolderPlus from '@mdi/svg/svg/folder-plus-outline.svg?raw'\nimport svgLink from '@mdi/svg/svg/link-plus.svg?raw'\nimport { Folder, Permission } from '@nextcloud/files'\nimport { generateRemoteUrl } from '@nextcloud/router'\nimport { ref } from 'vue'\n\nconst destination = new Folder({\n\tid: 42,\n\towner: 'admin',\n\tpermissions: Permission.ALL,\n\troot: '/files/admin',\n\tsource: generateRemoteUrl('dav/files/admin/Uploads'),\n})\n\nexport default {\n\tsetup() {\n\t\tconst lastAction = ref('')\n\n\t\treturn {\n\t\t\tdestination,\n\t\t\tlastAction,\n\n\t\t\t// The destination is empty, so no upload will ever conflict\n\t\t\tasync fetchContent() {\n\t\t\t\treturn []\n\t\t\t},\n\n\t\t\tactions: [\n\t\t\t\t{\n\t\t\t\t\tcaption: 'Create new',\n\t\t\t\t\tactions: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tlabel: 'New folder',\n\t\t\t\t\t\t\ticonSvg: svgFolderPlus,\n\t\t\t\t\t\t\tonClick: () => {\n\t\t\t\t\t\t\t\tlastAction.value = 'Clicked \"New folder\"'\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tlabel: 'Add from link',\n\t\t\t\t\t\t\ticonSvg: svgLink,\n\t\t\t\t\t\t\tonClick: () => {\n\t\t\t\t\t\t\t\tlastAction.value = 'Clicked \"Add from link\"'\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t],\n\t\t}\n\t},\n}\n</script>\n```\n\n### Controlling the uploader\n\nThe uploader itself is not owned by the picker, so it can also be controlled directly.\nThis is useful to pause the queue – picked files are queued but not uploaded until it is resumed –\nor to change the destination while the picker is mounted.\n\n```vue\n<template>\n\t<div class=\"uploader-controls\">\n\t\t<NcUploadPicker\n\t\t\tref=\"picker\"\n\t\t\t:content=\"fetchContent\"\n\t\t\t:destination=\"destination\"\n\t\t\tmultiple />\n\n\t\t<NcButton @click=\"uploader.pause()\">\n\t\t\tPause\n\t\t</NcButton>\n\t\t<NcButton @click=\"uploader.start()\">\n\t\t\tResume\n\t\t</NcButton>\n\t</div>\n</template>\n<script>\nimport { Folder, Permission } from '@nextcloud/files'\nimport { getUploader } from '@nextcloud/files/upload'\nimport { generateRemoteUrl } from '@nextcloud/router'\n\n/**\n * Create a folder for the given path within the users files.\n *\n * @param {string} path - Path of the folder, e.g. `/Documents`\n */\nfunction createFolder(path) {\n\treturn new Folder({\n\t\tid: 42,\n\t\towner: 'admin',\n\t\tpermissions: Permission.ALL,\n\t\troot: '/files/admin',\n\t\tsource: generateRemoteUrl(`dav/files/admin${path}`),\n\t})\n}\n\nexport default {\n\tsetup() {\n\t\treturn {\n\t\t\tdestination: createFolder('/Uploads'),\n\t\t\totherDestination: createFolder('/Documents'),\n\t\t\tuploader: getUploader(),\n\n\t\t\tasync fetchContent() {\n\t\t\t\treturn []\n\t\t\t},\n\t\t}\n\t},\n}\n</script>\n<style scoped>\n.uploader-controls {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 8px;\n\talign-items: center;\n}\n</style>\n```\n</docs>\n"],"names":["_createBlock","_unref","_createVNode","_createElementVNode","_normalizeClass","$style","_openBlock","_createElementBlock","_createTextVNode","_toDisplayString"],"mappings":"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","x_google_ignoreList":[0]}
|
|
1
|
+
{"version":3,"file":"NcUploadPicker.mjs","sources":["../../node_modules/@nextcloud/paths/dist/index.mjs","../../src/components/NcUploadPicker/NcUploadPicker.vue"],"sourcesContent":["function encodePath(path) {\n if (!path) {\n return path;\n }\n return path.split(\"/\").map(encodeURIComponent).join(\"/\");\n}\nfunction basename(path, extname2) {\n path = path.replace(/\\\\/g, \"/\").replace(/\\/+$/g, \"\").replace(/.*\\//, \"\");\n if (extname2 && extname2 !== path && path.endsWith(extname2)) {\n return path.substring(0, path.length - extname2.length);\n }\n return path;\n}\nfunction dirname(path) {\n path = path.replaceAll(/\\\\/g, \"/\");\n const sections = path.split(\"/\");\n if (sections.length <= 1) {\n return \".\";\n }\n sections.pop();\n if (sections.length === 1 && sections[0] === \"\") {\n return \"/\";\n }\n return sections.join(\"/\");\n}\nfunction extname(path) {\n const base = basename(path);\n const index = base.lastIndexOf(\".\");\n if (index > 0) {\n return base.substring(index);\n }\n return \"\";\n}\nfunction join(...args) {\n if (arguments.length < 1) {\n return \"\";\n }\n const nonEmptyArgs = args.filter((arg) => arg.length > 0);\n if (nonEmptyArgs.length < 1) {\n return \"\";\n }\n const lastArg = nonEmptyArgs[nonEmptyArgs.length - 1];\n const leadingSlash = nonEmptyArgs[0].charAt(0) === \"/\";\n const trailingSlash = lastArg.charAt(lastArg.length - 1) === \"/\";\n const sections = nonEmptyArgs.reduce((acc, section) => acc.concat(section.split(\"/\")), []);\n let first = !leadingSlash;\n const path = sections.reduce((acc, section) => {\n if (section === \"\") {\n return acc;\n }\n if (first) {\n first = false;\n return acc + section;\n }\n return acc + \"/\" + section;\n }, \"\");\n if (trailingSlash) {\n return path + \"/\";\n }\n return path;\n}\nfunction isSamePath(path1, path2) {\n const pathSections1 = (path1 || \"\").split(\"/\").filter((p) => p !== \".\");\n const pathSections2 = (path2 || \"\").split(\"/\").filter((p) => p !== \".\");\n path1 = join(...pathSections1);\n path2 = join(...pathSections2);\n return path1 === path2;\n}\nfunction normalize(path) {\n const sections = path.split(\"/\").filter((p, index, arr) => p !== \"\" || index === 0 || index === arr.length - 1).filter((p) => p !== \".\");\n const sanitizedSections = [];\n for (const section of sections) {\n const lastSection = sanitizedSections.at(-1);\n if (section === \"..\" && lastSection !== \"..\") {\n if (lastSection === void 0) {\n sanitizedSections.push(section);\n } else if (lastSection !== \"\") {\n sanitizedSections.pop();\n }\n } else {\n sanitizedSections.push(section);\n }\n }\n return sanitizedSections.join(\"/\");\n}\nexport {\n basename,\n dirname,\n encodePath,\n extname,\n isSamePath,\n join,\n normalize\n};\n//# sourceMappingURL=index.mjs.map\n","<!--\n - SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n\n<script setup lang=\"ts\">\nimport type { Folder, IFolder, INode } from '@nextcloud/files'\nimport type { IUpload } from '@nextcloud/files/upload'\nimport type { FilePickerItem, FilePickerItemGroup } from '../NcFilePicker/NcFilePicker.vue'\n\nimport { mdiClose, mdiPlus } from '@mdi/js'\nimport { openConflictPicker } from '@nextcloud/dialogs'\nimport { getUniqueName } from '@nextcloud/files'\nimport { getUploader, UploaderStatus, UploadStatus } from '@nextcloud/files/upload'\nimport { basename } from '@nextcloud/paths'\nimport { computed, onBeforeMount, onUnmounted, ref, useTemplateRef, watch } from 'vue'\nimport NcButton from '../NcButton/NcButton.vue'\nimport NcFilePicker from '../NcFilePicker/NcFilePicker.vue'\nimport NcIconSvgWrapper from '../NcIconSvgWrapper/NcIconSvgWrapper.vue'\nimport NcProgressBar from '../NcProgressBar/NcProgressBar.vue'\nimport { useFormatRelativeTime } from '../../composables/index.ts'\nimport { t } from '../../l10n.ts'\nimport { createElementId } from '../../utils/createElementId.ts'\nimport { logger } from '../../utils/logger.ts'\n\nconst props = withDefaults(defineProps<{\n\t/**\n\t * Actions to be shown in the upload picker menu.\n\t */\n\tactions?: FilePickerItem[] | FilePickerItemGroup[]\n\n\t/**\n\t * The upload destination folder\n\t */\n\tdestination: IFolder\n\n\t/**\n\t * A callback function to get the list of files present in the destination folder.\n\t */\n\tcontent: (relativePath?: string) => Promise<INode[]>\n\n\t/**\n\t * Allowed MIME types to upload\n\t */\n\taccept?: string[]\n\n\t/**\n\t * Disable the upload picker\n\t */\n\tdisabled?: boolean\n\n\t/**\n\t * The label of the upload picker button\n\t */\n\tlabel?: string\n\n\t/**\n\t * Allow uploading multiple files\n\t */\n\tmultiple?: boolean\n\n\t/**\n\t * Only show the icon without text label\n\t */\n\ticonOnly?: boolean\n\n\t/**\n\t * The variant of the menu button\n\t */\n\tvariant?: 'primary' | 'secondary' | 'tertiary'\n\n\t/**\n\t * Allow uploading directories\n\t */\n\tdirectory?: boolean\n}>(), {\n\tactions: () => [],\n\taccept: () => [],\n\tlabel: () => t('New'),\n\tvariant: 'secondary',\n})\n\nconst emit = defineEmits<{\n\t/**\n\t * Emitted when an upload has started.\n\t */\n\t'upload:started': [upload: IUpload]\n\t/**\n\t * Emitted when an upload has finished successfully.\n\t */\n\t'upload:finished': [upload: IUpload]\n\t/**\n\t * The queue has been paused, and no more uploads will be processed until resumed.\n\t */\n\tpaused: [queue: IUpload[]]\n\t/**\n\t * The queue has resumed uploading after being paused.\n\t */\n\tresumed: [queue: IUpload[]]\n\t/**\n\t * The queue has finished uploading all files.\n\t */\n\tfinished: []\n}>()\n\ndefineExpose({\n\treset,\n})\n\nconst filePickerElement = useTemplateRef('filePicker')\nconst progressTimeId = createElementId()\n\nconst uploadManager = getUploader()\nonBeforeMount(() => {\n\twindow.addEventListener('beforeunload', onBeforePageUnload)\n\tuploadManager.addEventListener('uploadFinished', onUploadFinished)\n\tuploadManager.addEventListener('uploadStarted', onUploadStarted)\n\tuploadManager.addEventListener('uploadProgress', updateEta)\n\tuploadManager.addEventListener('finished', onUploaderFinished)\n\tuploadManager.addEventListener('paused', onUploaderPaused)\n\tuploadManager.addEventListener('reset', updateUploadStatus)\n\tuploadManager.addEventListener('resumed', onUploaderResumed)\n\tupdateUploadStatus()\n})\nonUnmounted(() => {\n\twindow.removeEventListener('beforeunload', onBeforePageUnload)\n\tuploadManager.removeEventListener('uploadFinished', onUploadFinished)\n\tuploadManager.removeEventListener('uploadStarted', onUploadStarted)\n\tuploadManager.removeEventListener('uploadProgress', updateEta)\n\tuploadManager.removeEventListener('finished', onUploaderFinished)\n\tuploadManager.removeEventListener('paused', onUploaderPaused)\n\tuploadManager.removeEventListener('reset', updateUploadStatus)\n\tuploadManager.removeEventListener('resumed', onUploaderResumed)\n})\n\nwatch(() => props.destination, () => setDestination(props.destination), { immediate: true })\n\nconst isPaused = ref(uploadManager.status === UploaderStatus.PAUSED)\n/** Handle uploader paused event */\nfunction onUploaderPaused() {\n\tupdateUploadStatus()\n\temit('paused', [...uploadManager.queue])\n}\n/** Handle uploader resumed event */\nfunction onUploaderResumed() {\n\tupdateUploadStatus()\n\temit('resumed', [...uploadManager.queue])\n}\n\nconst hasFailure = ref(false)\nconst isUploading = ref(false)\nconst isAssembling = ref(false)\nconst isOnlyAssembling = ref(false)\n\n/**\n * Update the upload status flags based on the current queue\n */\nfunction updateUploadStatus() {\n\tisPaused.value = uploadManager.status === UploaderStatus.PAUSED\n\t// While paused the queue is not processed, but the queued uploads are still pending\n\tisUploading.value = uploadManager.status === UploaderStatus.UPLOADING\n\t\t|| (isPaused.value && uploadManager.queue.length > 0)\n\thasFailure.value = uploadManager.queue.some((upload: IUpload) => upload.status === UploadStatus.FAILED)\n\tisAssembling.value = uploadManager.queue.some((upload: IUpload) => upload.status === UploadStatus.ASSEMBLING)\n\t// only assembling if assembling at all AND all other uploads are already finished (or failed)\n\tisOnlyAssembling.value = isAssembling.value\n\t\t&& uploadManager.queue.every((upload: IUpload) => upload.status >= UploadStatus.ASSEMBLING)\n}\n\n/**\n * Reset the file input form\n */\nfunction reset() {\n\tfilePickerElement.value?.reset()\n}\n\n/**\n * Set the upload destination\n *\n * @param destination - The new upload destination\n */\nfunction setDestination(destination: IFolder) {\n\tif (!destination) {\n\t\tlogger.debug('Invalid destination')\n\t\treturn\n\t}\n\n\tuploadManager.destination = destination as Folder\n}\n\nconst etaProgress = ref(0)\nconst etaSpeed = ref('')\nconst etaRaw = ref<number>(Infinity)\nconst etaTimeRaw = computed(() => etaRaw.value === Infinity ? Infinity : new Date(Date.now() + etaRaw.value))\nconst etaTimeFormatted = useFormatRelativeTime(etaTimeRaw, { ignoreSeconds: true })\nconst etaTime = computed(() => etaTimeRaw.value === Infinity ? t('Estimating …') : etaTimeFormatted.value)\n/** Update the ETA and speed values */\nfunction updateEta() {\n\tetaRaw.value = uploadManager.statistics.eta === Infinity ? Infinity : (uploadManager.statistics.eta * 1000)\n\tetaSpeed.value = uploadManager.statistics.speedReadable\n\tetaProgress.value = uploadManager.statistics.progress\n}\n\n/**\n * Handle uploader finished event\n */\nfunction onUploaderFinished() {\n\tupdateUploadStatus()\n\temit('finished')\n}\n\n/**\n * Handle upload finished event\n *\n * @param event - The upload finished event\n */\nfunction onUploadFinished(event: CustomEvent<IUpload>) {\n\tupdateUploadStatus()\n\temit('upload:finished', event.detail)\n}\n\n/**\n * Handle upload started event\n *\n * @param event - The upload started event\n */\nfunction onUploadStarted(event: CustomEvent<IUpload>) {\n\tupdateUploadStatus()\n\temit('upload:started', event.detail)\n}\n\n/**\n * Start uploading\n *\n * @param files - The files to upload\n */\nasync function onPick(files: File[]) {\n\ttry {\n\t\tawait uploadManager\n\t\t\t.batchUpload('', files, { callback: handleConflicts })\n\t} catch (error) {\n\t\tlogger.debug('Error while uploading', { error })\n\t} finally {\n\t\treset()\n\t}\n}\n\n/**\n * Handle conflicts during upload\n *\n * @param nodes - The nodes that might conflict\n * @param currentPath - The path of the current directory\n */\nasync function handleConflicts(nodes: string[], currentPath: string): Promise<Record<string, string> | false> {\n\ttry {\n\t\tconst content = await props.content(currentPath)\n\t\tconst conflicts = content.filter((node) => nodes.includes(node.displayname) || nodes.includes(node.basename))\n\t\tconst uploadMapping = Object.fromEntries(nodes.map((name) => [name, name]))\n\t\tif (conflicts.length === 0) {\n\t\t\treturn uploadMapping\n\t\t}\n\n\t\t// The conflict picker requires the incoming and the existing nodes to be aligned,\n\t\t// so the existing content has to be filtered to only contain the conflicting nodes.\n\t\tconst existingNodes = content.filter((node) => nodes.includes(node.displayname) || nodes.includes(node.basename))\n\t\tconst result = await openConflictPicker(basename(currentPath), conflicts, existingNodes, { recursive: props.directory })\n\t\tif (result) {\n\t\t\tconst usedNames = content.map((node) => node.basename)\n\t\t\tfor (const node of conflicts) {\n\t\t\t\tif ((result.skipped as unknown as INode[]).some((skipped) => skipped.basename === node.basename)) {\n\t\t\t\t\tdelete uploadMapping[node.basename]\n\t\t\t\t} else if ((result.renamed as unknown as INode[]).some((renamed) => renamed.basename === node.basename)) {\n\t\t\t\t\tconst newName = getUniqueName(basename(node.basename), usedNames)\n\t\t\t\t\tuploadMapping[node.basename] = newName\n\t\t\t\t\tusedNames.push(newName)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn uploadMapping\n\t\t}\n\t} catch (error) {\n\t\tlogger.error('Error during conflict resolution - skipping upload', { error })\n\t}\n\treturn false\n}\n\n/**\n * Cancel ongoing queue\n */\nfunction onCancel() {\n\tuploadManager.reset()\n\treset()\n}\n\n/**\n * Handle page unload.\n * Block the unload if there are ongoing uploads.\n *\n * @param event - The event\n */\nfunction onBeforePageUnload(event: BeforeUnloadEvent) {\n\tif (uploadManager.queue.length > 0) {\n\t\tevent.preventDefault()\n\t\tevent.returnValue = ''\n\t}\n}\n</script>\n\n<template>\n\t<NcFilePicker\n\t\tref=\"filePicker\"\n\t\t:accept\n\t\t:actionCaption=\"actions.length > 0 || directory ? t('Upload from device') : undefined\"\n\t\t:actions\n\t\t:directory\n\t\t:disabled\n\t\t:iconOnly\n\t\t:label\n\t\t:multiple\n\t\t:variant\n\t\t@pick=\"onPick\">\n\t\t<template #icon>\n\t\t\t<NcIconSvgWrapper :path=\"mdiPlus\" />\n\t\t</template>\n\n\t\t<!-- Progressbar and status -->\n\t\t<div\n\t\t\tv-show=\"isUploading\"\n\t\t\t:class=\"[$style.uploadPicker_progress, {\n\t\t\t\t[$style.uploadPicker_progress__uploading]: isUploading,\n\t\t\t\t[$style.uploadPicker_progress__paused]: isPaused,\n\t\t\t}]\">\n\t\t\t<NcProgressBar\n\t\t\t\t:ariaLabel=\"t('Upload progress')\"\n\t\t\t\t:ariaDescribedby=\"progressTimeId\"\n\t\t\t\t:error=\"hasFailure\"\n\t\t\t\t:value=\"etaProgress\"\n\t\t\t\tsize=\"medium\" />\n\t\t\t<p :id=\"progressTimeId\" :class=\"$style.uploadPicker_progressLabel\">\n\t\t\t\t<span v-if=\"isPaused\">\n\t\t\t\t\t{{ t('paused') /* TRANSLATORS: State of the current upload - it is paused */ }}\n\t\t\t\t</span>\n\t\t\t\t<span v-else-if=\"isOnlyAssembling\">\n\t\t\t\t\t{{ t('assembling') /* TRANSLATORS: State of the current upload - chunks of the uploaded files are being assembled into the final file */ }}\n\t\t\t\t</span>\n\t\t\t\t<span v-else :title=\"`${etaTime} (${etaSpeed})`\">\n\t\t\t\t\t{{ etaTime }}\n\t\t\t\t\t<!-- the speed is included in the tooltip / title so we only show it in the text content if there is enough space (not showing \"a few seconds left\") -->\n\t\t\t\t\t<span v-if=\"etaSpeed && etaRaw > 31000\" :class=\"$style.uploadPicker_progressLabelSpeed\">\n\t\t\t\t\t\t({{ etaSpeed }})\n\t\t\t\t\t</span>\n\t\t\t\t</span>\n\t\t\t</p>\n\t\t</div>\n\n\t\t<!-- Cancel upload button -->\n\t\t<NcButton\n\t\t\tv-if=\"isUploading && !isOnlyAssembling\"\n\t\t\t:class=\"$style.uploadPicker_cancelButton\"\n\t\t\t:aria-label=\"t('Cancel uploads')\"\n\t\t\tvariant=\"tertiary\"\n\t\t\t@click=\"onCancel\">\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</NcFilePicker>\n</template>\n\n<style module>\n.uploadPicker_progress {\n\t--upload-picker-progress-width: 200px;\n\twidth: var(--upload-picker-progress-width);\n\t/* Animate show/hide */\n\tmax-width: 0;\n\ttransition: max-width var(--animation-quick) ease-in-out;\n\t/* Align progress/text separation with the middle */\n\tmargin-top: 8px;\n}\n\n.uploadPicker_progress__uploading {\n\tmax-width: var(--upload-picker-progress-width);\n\n\t/* Visually more pleasing spacing */\n\tmargin-inline: 8px 20px;\n}\n\n.uploadPicker_progress__paused {\n\tanimation: breathing 3s ease-out infinite normal;\n}\n\n.uploadPicker_progressLabel {\n\toverflow: hidden;\n\twhite-space: nowrap;\n\ttext-overflow: ellipsis;\n}\n\n.uploadPicker_progressLabelSpeed{\n\tcolor: var(--color-text-maxcontrast);\n}\n\n@keyframes breathing {\n\t0% {\n\t\topacity: .5;\n\t}\n\t25% {\n\t\topacity: 1;\n\t}\n\t60% {\n\t\topacity: .5;\n\t}\n\t100% {\n\t\topacity: .5;\n\t}\n}\n</style>\n\n<docs>\n## Requirements\n\nTo use the `NcUploadPicker` component, you need to install the following packages:\n- `@nextcloud/dialogs`\n- `@nextcloud/files`\n\n## Usage\n\nThe upload picker lets users pick files – or whole directories – from their device and uploads them\nto a folder on the Nextcloud server, using the shared uploader of `@nextcloud/files/upload`.\nWhile uploading it shows the progress, the estimated remaining time and a button to cancel all queued uploads.\n\nTwo props are required to set it up:\n\n- `destination`: The folder to upload into, as an `IFolder` of `@nextcloud/files`.\n- `content`: A callback that resolves with the nodes that already exist in a folder that is uploaded into.\n It is called with the path relative to the `destination` – the empty string for the destination itself –\n and is used to detect upload conflicts. If there are conflicts, the user is asked to skip or rename\n the conflicting files.\n\n### Exposed methods\n\n- `function reset(): void`\n Reset the internal state of the picker, e.g. to clear the current selection.\n\n**Note**: All upload pickers share the global uploader instance of `getUploader()`,\nincluding its queue and its destination. Because of that only a single upload picker\nshould be mounted at a time – in the examples below the picker that was mounted last defines the destination.\n\n**Note about the examples**: There is no Nextcloud server behind the styleguide,\nso the examples use a fake WebDAV server that simulates slow – but always successful – uploads.\nUploading a file called `Photo.jpg` or `Notes.md` triggers the conflict dialog,\nfiles larger than 10 MiB are uploaded in chunks.\n\n### Basic usage\n\n```vue\n<template>\n\t<div>\n\t\t<NcUploadPicker\n\t\t\t:content=\"fetchContent\"\n\t\t\t:destination=\"destination\"\n\t\t\tmultiple\n\t\t\t@finished=\"log('finished')\"\n\t\t\t@upload:finished=\"log('upload:finished', $event)\"\n\t\t\t@upload:started=\"log('upload:started', $event)\" />\n\n\t\t<NcNoteCard v-if=\"events.length === 0\" type=\"info\">\n\t\t\tPick some files to upload them to <code>{{ destination.path }}</code>.\n\t\t</NcNoteCard>\n\t\t<ul v-else>\n\t\t\t<li v-for=\"(event, index) in events\" :key=\"index\">\n\t\t\t\t{{ event }}\n\t\t\t</li>\n\t\t</ul>\n\t</div>\n</template>\n<script>\nimport { File as NcFile, Folder, Permission } from '@nextcloud/files'\nimport { generateRemoteUrl } from '@nextcloud/router'\nimport { ref } from 'vue'\n\n// The folder the picked files are uploaded into\nconst destination = new Folder({\n\tid: 42,\n\towner: 'admin',\n\tpermissions: Permission.ALL,\n\troot: '/files/admin',\n\tsource: generateRemoteUrl('dav/files/admin/Uploads'),\n})\n\n// The nodes that already exist in the destination, in a real app this is the result of a PROPFIND\nconst existingNodes = ['Photo.jpg', 'Notes.md'].map((name) => new NcFile({\n\tmime: 'application/octet-stream',\n\towner: 'admin',\n\troot: '/files/admin',\n\tsource: `${destination.source}/${name}`,\n}))\n\nexport default {\n\tsetup() {\n\t\tconst events = ref([])\n\n\t\treturn {\n\t\t\tdestination,\n\t\t\tevents,\n\n\t\t\t// Provide the content of the folder that is uploaded into to allow detecting conflicts\n\t\t\tasync fetchContent(relativePath) {\n\t\t\t\t// Folders created by the upload itself are empty, so they never conflict\n\t\t\t\treturn relativePath ? [] : existingNodes\n\t\t\t},\n\n\t\t\tlog(name, upload) {\n\t\t\t\t// One `upload:*` event is emitted for the destination itself - shown as `/` - and one per picked file\n\t\t\t\tconst path = upload && decodeURIComponent(upload.source.slice(destination.source.length))\n\t\t\t\tevents.value.unshift(upload ? `${name}: ${path}` : name)\n\t\t\t},\n\t\t}\n\t},\n}\n</script>\n```\n\n### Directories and custom actions\n\nSetting `directory` adds an entry to upload a whole directory tree, which is recreated in the destination.\nAdditional entries – like the \"New folder\" action of the Files app – can be added using the `actions` prop,\neither as a flat list or grouped with a caption.\nThe `accept` prop restricts the file types that can be picked.\n\n```vue\n<template>\n\t<div>\n\t\t<NcUploadPicker\n\t\t\t:accept=\"['image/jpeg', 'image/png']\"\n\t\t\t:actions=\"actions\"\n\t\t\t:content=\"fetchContent\"\n\t\t\t:destination=\"destination\"\n\t\t\tdirectory\n\t\t\tlabel=\"Add media\"\n\t\t\tmultiple\n\t\t\tvariant=\"primary\" />\n\n\t\t<NcNoteCard v-if=\"lastAction\" type=\"success\">\n\t\t\t{{ lastAction }}\n\t\t</NcNoteCard>\n\t</div>\n</template>\n<script>\nimport svgFolderPlus from '@mdi/svg/svg/folder-plus-outline.svg?raw'\nimport svgLink from '@mdi/svg/svg/link-plus.svg?raw'\nimport { Folder, Permission } from '@nextcloud/files'\nimport { generateRemoteUrl } from '@nextcloud/router'\nimport { ref } from 'vue'\n\nconst destination = new Folder({\n\tid: 42,\n\towner: 'admin',\n\tpermissions: Permission.ALL,\n\troot: '/files/admin',\n\tsource: generateRemoteUrl('dav/files/admin/Uploads'),\n})\n\nexport default {\n\tsetup() {\n\t\tconst lastAction = ref('')\n\n\t\treturn {\n\t\t\tdestination,\n\t\t\tlastAction,\n\n\t\t\t// The destination is empty, so no upload will ever conflict\n\t\t\tasync fetchContent() {\n\t\t\t\treturn []\n\t\t\t},\n\n\t\t\tactions: [\n\t\t\t\t{\n\t\t\t\t\tcaption: 'Create new',\n\t\t\t\t\tactions: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tlabel: 'New folder',\n\t\t\t\t\t\t\ticonSvg: svgFolderPlus,\n\t\t\t\t\t\t\tonClick: () => {\n\t\t\t\t\t\t\t\tlastAction.value = 'Clicked \"New folder\"'\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tlabel: 'Add from link',\n\t\t\t\t\t\t\ticonSvg: svgLink,\n\t\t\t\t\t\t\tonClick: () => {\n\t\t\t\t\t\t\t\tlastAction.value = 'Clicked \"Add from link\"'\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t],\n\t\t}\n\t},\n}\n</script>\n```\n\n### Controlling the uploader\n\nThe uploader itself is not owned by the picker, so it can also be controlled directly.\nThis is useful to pause the queue – picked files are queued but not uploaded until it is resumed –\nor to change the destination while the picker is mounted.\n\n```vue\n<template>\n\t<div class=\"uploader-controls\">\n\t\t<NcUploadPicker\n\t\t\tref=\"picker\"\n\t\t\t:content=\"fetchContent\"\n\t\t\t:destination=\"destination\"\n\t\t\tmultiple />\n\n\t\t<NcButton @click=\"uploader.pause()\">\n\t\t\tPause\n\t\t</NcButton>\n\t\t<NcButton @click=\"uploader.start()\">\n\t\t\tResume\n\t\t</NcButton>\n\t</div>\n</template>\n<script>\nimport { Folder, Permission } from '@nextcloud/files'\nimport { getUploader } from '@nextcloud/files/upload'\nimport { generateRemoteUrl } from '@nextcloud/router'\n\n/**\n * Create a folder for the given path within the users files.\n *\n * @param {string} path - Path of the folder, e.g. `/Documents`\n */\nfunction createFolder(path) {\n\treturn new Folder({\n\t\tid: 42,\n\t\towner: 'admin',\n\t\tpermissions: Permission.ALL,\n\t\troot: '/files/admin',\n\t\tsource: generateRemoteUrl(`dav/files/admin${path}`),\n\t})\n}\n\nexport default {\n\tsetup() {\n\t\treturn {\n\t\t\tdestination: createFolder('/Uploads'),\n\t\t\totherDestination: createFolder('/Documents'),\n\t\t\tuploader: getUploader(),\n\n\t\t\tasync fetchContent() {\n\t\t\t\treturn []\n\t\t\t},\n\t\t}\n\t},\n}\n</script>\n<style scoped>\n.uploader-controls {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 8px;\n\talign-items: center;\n}\n</style>\n```\n</docs>\n"],"names":["_createBlock","_unref","_createVNode","_createElementVNode","_normalizeClass","$style","_openBlock","_createElementBlock","_createTextVNode","_toDisplayString"],"mappings":"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","x_google_ignoreList":[0]}
|