Merge pull request #40266 from nextcloud/40172-polish-new-sharing-flow

40172 Polish new sharing flow :  accesibility, expand bahavior, click outside behaviour
This commit is contained in:
Andy Scherzinger 2023-09-07 12:57:24 +02:00 committed by GitHub
commit a0c4935e32
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 116 additions and 24 deletions

View file

@ -1,16 +1,30 @@
<template>
<div :class="{ 'active': showDropdown, 'share-select': true }">
<span class="trigger-text" @click="toggleDropdown">
<div ref="quickShareDropdownContainer"
:class="{ 'active': showDropdown, 'share-select': true }">
<span :id="dropdownId"
class="trigger-text"
:aria-expanded="showDropdown"
:aria-haspopup="true"
aria-label="Quick share options dropdown"
@click="toggleDropdown">
{{ selectedOption }}
<DropdownIcon :size="15" />
</span>
<div v-if="showDropdown" class="share-select-dropdown-container">
<div v-for="option in options"
<div v-if="showDropdown"
ref="quickShareDropdown"
class="share-select-dropdown"
:aria-labelledby="dropdownId"
tabindex="0"
@keydown.down="handleArrowDown"
@keydown.up="handleArrowUp"
@keydown.esc="closeDropdown">
<button v-for="option in options"
:key="option"
:class="{ 'dropdown-item': true, 'selected': option === selectedOption }"
:aria-selected="option === selectedOption"
@click="selectOption(option)">
{{ option }}
</div>
</button>
</div>
</div>
</template>
@ -26,6 +40,8 @@ import {
ATOMIC_PERMISSIONS,
} from '../lib/SharePermissionsToolBox.js'
import { createFocusTrap } from 'focus-trap'
export default {
components: {
DropdownIcon,
@ -45,6 +61,7 @@ export default {
return {
selectedOption: '',
showDropdown: this.toggle,
focusTrap: null,
}
},
computed: {
@ -102,6 +119,10 @@ export default {
return BUNDLED_PERMISSIONS.READ_ONLY
}
},
dropdownId() {
// Generate a unique ID for ARIA attributes
return `dropdown-${Math.random().toString(36).substr(2, 9)}`
},
},
watch: {
toggle(toggleValue) {
@ -110,10 +131,26 @@ export default {
},
mounted() {
this.initializeComponent()
window.addEventListener('click', this.handleClickOutside)
},
beforeDestroy() {
// Remove the global click event listener to prevent memory leaks
window.removeEventListener('click', this.handleClickOutside)
},
methods: {
toggleDropdown() {
this.showDropdown = !this.showDropdown
if (this.showDropdown) {
this.$nextTick(() => {
this.useFocusTrap()
})
} else {
this.clearFocusTrap()
}
},
closeDropdown() {
this.clearFocusTrap()
this.showDropdown = false
},
selectOption(option) {
this.selectedOption = option
@ -128,6 +165,51 @@ export default {
initializeComponent() {
this.selectedOption = this.preSelectedOption
},
handleClickOutside(event) {
const dropdownContainer = this.$refs.quickShareDropdownContainer
if (dropdownContainer && !dropdownContainer.contains(event.target)) {
this.showDropdown = false
}
},
useFocusTrap() {
// Create global stack if undefined
// Use in with trapStack to avoid conflicting traps
Object.assign(window, { _nc_focus_trap: window._nc_focus_trap || [] })
const dropdownElement = this.$refs.quickShareDropdown
this.focusTrap = createFocusTrap(dropdownElement, {
allowOutsideClick: true,
trapStack: window._nc_focus_trap,
})
this.focusTrap.activate()
},
clearFocusTrap() {
this.focusTrap?.deactivate()
this.focusTrap = null
},
shiftFocusForward() {
const currentElement = document.activeElement
let nextElement = currentElement.nextElementSibling
if (!nextElement) {
nextElement = this.$refs.quickShareDropdown.firstElementChild
}
nextElement.focus()
},
shiftFocusBackward() {
const currentElement = document.activeElement
let previousElement = currentElement.previousElementSibling
if (!previousElement) {
previousElement = this.$refs.quickShareDropdown.lastElementChild
}
previousElement.focus()
},
handleArrowUp() {
this.shiftFocusBackward()
},
handleArrowDown() {
this.shiftFocusForward()
},
},
}
@ -147,8 +229,10 @@ export default {
color: var(--color-primary-element);
}
.share-select-dropdown-container {
.share-select-dropdown {
position: absolute;
display: flex;
flex-direction: column;
top: 100%;
left: 0;
background-color: var(--color-main-background);
@ -160,6 +244,16 @@ export default {
.dropdown-item {
padding: 8px;
font-size: 12px;
background: none;
border: none;
border-radius: 0;
font: inherit;
cursor: pointer;
color: inherit;
outline: none;
width: 100%;
white-space: nowrap;
text-align: left;
&:hover {
background-color: #f2f2f2;
@ -172,13 +266,13 @@ export default {
}
/* Optional: Add a transition effect for smoother dropdown animation */
.share-select-dropdown-container {
.share-select-dropdown {
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease;
}
&.active .share-select-dropdown-container {
&.active .share-select-dropdown {
max-height: 200px;
/* Adjust the value to your desired height */
}

View file

@ -61,7 +61,7 @@
name="sharing_permission_radio"
type="radio"
button-variant-grouped="vertical"
@update:checked="toggleCustomPermissions">
@update:checked="expandCustomPermissions">
{{ t('files_sharing', 'Custom permissions') }}
<small>{{ t('files_sharing', customPermissionsList) }}</small>
<template #icon>
@ -666,16 +666,14 @@ export default {
this.$set(this.share, 'hasDownloadPermission', isDownloadChecked)
}
},
toggleCustomPermissions(selectedPermission) {
if (this.sharingPermission === 'custom') {
expandCustomPermissions() {
if (!this.advancedSectionAccordionExpanded) {
this.advancedSectionAccordionExpanded = true
this.setCustomPermissions = true
} else {
this.advancedSectionAccordionExpanded = false
this.revertSharingPermission = selectedPermission
this.setCustomPermissions = false
}
this.toggleCustomPermissions()
},
toggleCustomPermissions() {
this.setCustomPermissions = this.sharingPermission === 'custom'
},
initializeAttributes() {

3
dist/2079-2079.js vendored Normal file

File diff suppressed because one or more lines are too long

1
dist/2079-2079.js.map vendored Normal file

File diff suppressed because one or more lines are too long

3
dist/894-894.js vendored

File diff suppressed because one or more lines are too long

1
dist/894-894.js.map vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long