Skip to content

Commit

Permalink
Merge pull request #4909 from nextcloud-libraries/fix/sidebar-focus-t…
Browse files Browse the repository at this point in the history
…rap-on-mobile

fix(NcAppSidebar): add focus trap on mobile
  • Loading branch information
ShGKme committed Dec 11, 2023
2 parents d6a6cb7 + 66d0264 commit dd79bf8
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 15 deletions.
31 changes: 18 additions & 13 deletions src/components/NcAppNavigationToggle/NcAppNavigationToggle.vue
Expand Up @@ -22,18 +22,20 @@
-
-->
<template>
<NcButton class="app-navigation-toggle"
type="tertiary"
:aria-expanded="open ? 'true' : 'false'"
:aria-label="label"
:title="label"
aria-controls="app-navigation-vue"
@click="toggleNavigation">
<template #icon>
<MenuOpenIcon v-if="open" :size="20" />
<MenuIcon v-else :size="20" />
</template>
</NcButton>
<div class="app-navigation-toggle-wrapper">
<NcButton class="app-navigation-toggle"
type="tertiary"
:aria-expanded="open ? 'true' : 'false'"
:aria-label="label"
:title="label"
aria-controls="app-navigation-vue"
@click="toggleNavigation">
<template #icon>
<MenuOpenIcon v-if="open" :size="20" />
<MenuIcon v-else :size="20" />
</template>
</NcButton>
</div>
</template>

<script>
Expand Down Expand Up @@ -75,11 +77,14 @@ export default {
</script>

<style scoped lang="scss">
button.app-navigation-toggle {
.app-navigation-toggle-wrapper {
position: absolute;
top: var(--app-navigation-padding);
right: calc(0px - var(--app-navigation-padding));
margin-right: - $clickable-area;
}
button.app-navigation-toggle {
background-color: var(--color-main-background);
}
</style>
61 changes: 59 additions & 2 deletions src/components/NcAppSidebar/NcAppSidebar.vue
Expand Up @@ -345,7 +345,10 @@ export default {
@after-enter="onAfterEnter"
@before-leave="onBeforeLeave"
@after-leave="onAfterLeave">
<aside id="app-sidebar-vue" class="app-sidebar">
<aside id="app-sidebar-vue"
ref="sidebar"
class="app-sidebar"
@keydown.esc.stop="isMobile && closeSidebar()">
<header :class="{
'app-sidebar-header--with-figure': hasFigure,
'app-sidebar-header--compact': compact,
Expand Down Expand Up @@ -447,7 +450,8 @@ export default {
</div>
</div>

<NcButton :title="closeTranslated"
<NcButton ref="closeButton"
:title="closeTranslated"
:aria-label="closeTranslated"
type="tertiary"
class="app-sidebar__close"
Expand Down Expand Up @@ -487,6 +491,8 @@ import NcEmptyContent from '../NcEmptyContent/index.js'
import Focus from '../../directives/Focus/index.js'
import Linkify from '../../directives/Linkify/index.js'
import Tooltip from '../../directives/Tooltip/index.js'
import { useIsSmallMobile } from '../../composables/useIsMobile/index.js'
import { getTrapStack } from '../../utils/focusTrap.js'
import { t } from '../../l10n.js'
import ArrowRight from 'vue-material-design-icons/ArrowRight.vue'
Expand All @@ -495,6 +501,7 @@ import Star from 'vue-material-design-icons/Star.vue'
import StarOutline from 'vue-material-design-icons/StarOutline.vue'
import { vOnClickOutside as ClickOutside } from '@vueuse/components'
import { createFocusTrap } from 'focus-trap'
export default {
name: 'NcAppSidebar',
Expand Down Expand Up @@ -641,12 +648,19 @@ export default {
'dismiss-editing',
],
setup() {
return {
isMobile: useIsSmallMobile(),
}
},
data() {
return {
changeNameTranslated: t('Change name'),
closeTranslated: t('Close sidebar'),
favoriteTranslated: t('Favorite'),
isStarred: this.starred,
focusTrap: null,
}
},
Expand All @@ -666,14 +680,57 @@ export default {
starred() {
this.isStarred = this.starred
},
isMobile() {
this.toggleFocusTrap()
},
},
mounted() {
this.toggleFocusTrap()
},
beforeDestroy() {
// Make sure that the 'closed' event is dispatched even if this element is destroyed before the 'after-leave' event is received.
this.$emit('closed')
this.focusTrap?.deactivate()
},
methods: {
initFocusTrap() {
if (this.focusTrap) {
return
}
this.focusTrap = createFocusTrap([
// The sidebar itself
this.$refs.sidebar,
// Nextcloud Server header navigarion
document.querySelector('#header'),
// The app navigation toggle. Navigation can be opened above the sidebar
// Take the parent element, because the focus-trap requires a container with elements, not the element itself
document.querySelector('[aria-controls="app-navigation-vue"]')?.parentElement,
], {
allowOutsideClick: true,
fallbackFocus: this.$refs.closeButton,
trapStack: getTrapStack(),
escapeDeactivates: false,
})
},
/**
* Activate focus trap if it is currently needed, otherwise deactivate
*/
toggleFocusTrap() {
console.debug('toggleFocusTrap', this.isMobile)
if (this.isMobile) {
this.initFocusTrap()
this.focusTrap.activate()
} else {
this.focusTrap?.deactivate()
}
},
onBeforeEnter(element) {
/**
* The sidebar is opening and the transition is in progress
Expand Down

0 comments on commit dd79bf8

Please sign in to comment.