Skip to content

Commit

Permalink
fix(NcPopover): intercept into current focus trap stack
Browse files Browse the repository at this point in the history
Signed-off-by: Grigorii K. Shartsev <me@shgk.me>
  • Loading branch information
ShGKme committed Jan 25, 2024
1 parent 20577bc commit 9463ffc
Showing 1 changed file with 35 additions and 14 deletions.
49 changes: 35 additions & 14 deletions src/components/NcPopover/NcPopover.vue
Original file line number Diff line number Diff line change
Expand Up @@ -157,13 +157,14 @@ See: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/

<template>
<Dropdown ref="popover"
:shown.sync="shownProxy"
:distance="10"
:arrow-padding="10"
v-bind="$attrs"
:no-auto-focus="true /* Handled by the focus trap */"
:popper-class="popoverBaseClass"
:shown="internalShown"
v-on="$listeners"
@update:shown="internalShown = $event"
@apply-show="afterShow"
@apply-hide="afterHide">
<NcPopoverTriggerProvider v-slot="slotProps" :shown="internalShown" :popup-role="popupRole">
Expand Down Expand Up @@ -249,25 +250,19 @@ export default {
data() {
return {
internalShown: this.shown,
externalFocusTrapStack: [],
}
},
computed: {
shownProxy: {
get() {
return this.shown
},
set(value) {
this.internalShown = value
this.$emit('update:shown', value)
},
},
},
watch: {
shown(value) {
this.internalShown = value
},
internalShown(value) {
this.$emit('update:shown', value)
this.intersectIntoCurrentFocusTrapStack()
},
},
mounted() {
Expand Down Expand Up @@ -319,7 +314,7 @@ export default {
return
}
// Init focus trap
// Init own focus trap
this.$focusTrap = createFocusTrap(el, {
// Prevents to lose focus using esc key
// Focus will be release when popover be hide
Expand Down Expand Up @@ -374,6 +369,31 @@ export default {
}
},
/**
* If the component has its own focus trap, then it is managed by global trap stack by focus-trap.
*
* But if the component has no focus trap and used inside another focus trap - there is an issue.
* By default popover content is rendered in body or other container, which is likely outside the current focus trap containers.
* We need pause the focus-trap for opening popover and then unpause it after closing.
*/
intersectIntoCurrentFocusTrapStack() {
if (this.focusTrap) {
return
}
if (this.internalShown) {
this.externalFocusTrapStack = [...getTrapStack()]
for (const trap of this.externalFocusTrapStack) {
trap.pause()
}
} else {
for (const trap of this.externalFocusTrapStack) {
trap.unpause()
}
this.externalFocusTrapStack = []
}
},
afterShow() {
/**
* Triggered after the tooltip was visually displayed.
Expand All @@ -388,6 +408,7 @@ export default {
this.addEscapeStopPropagation()
})
},
afterHide() {
/**
* Triggered after the tooltip was visually hidden.
Expand Down

0 comments on commit 9463ffc

Please sign in to comment.