Skip to content

Commit

Permalink
Merge pull request #40266 from nextcloud/40172-polish-new-sharing-flow
Browse files Browse the repository at this point in the history
40172 Polish new sharing flow :  accesibility, expand bahavior, click outside behaviour
  • Loading branch information
AndyScherzinger authored Sep 7, 2023
2 parents 8549ea4 + cad1db8 commit a0c4935
Show file tree
Hide file tree
Showing 9 changed files with 116 additions and 24 deletions.
110 changes: 102 additions & 8 deletions apps/files_sharing/src/components/SharingEntryQuickShareSelect.vue
Original file line number Diff line number Diff line change
@@ -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>
Expand All @@ -26,6 +40,8 @@ import {
ATOMIC_PERMISSIONS,
} from '../lib/SharePermissionsToolBox.js'
import { createFocusTrap } from 'focus-trap'
export default {
components: {
DropdownIcon,
Expand All @@ -45,6 +61,7 @@ export default {
return {
selectedOption: '',
showDropdown: this.toggle,
focusTrap: null,
}
},
computed: {
Expand Down Expand Up @@ -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) {
Expand All @@ -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
Expand All @@ -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()
},
},
}
Expand All @@ -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);
Expand All @@ -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;
Expand All @@ -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 */
}
Expand Down
16 changes: 7 additions & 9 deletions apps/files_sharing/src/views/SharingDetailsTab.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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() {
Expand Down
3 changes: 3 additions & 0 deletions dist/2079-2079.js

Large diffs are not rendered by default.

File renamed without changes.
1 change: 1 addition & 0 deletions dist/2079-2079.js.map

Large diffs are not rendered by default.

3 changes: 0 additions & 3 deletions dist/894-894.js

This file was deleted.

1 change: 0 additions & 1 deletion dist/894-894.js.map

This file was deleted.

4 changes: 2 additions & 2 deletions dist/files_sharing-files_sharing_tab.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/files_sharing-files_sharing_tab.js.map

Large diffs are not rendered by default.

0 comments on commit a0c4935

Please sign in to comment.