Skip to content

Commit

Permalink
feat(NcPopover): auto return focus to trigger button on close
Browse files Browse the repository at this point in the history
Signed-off-by: Grigorii K. Shartsev <[email protected]>
  • Loading branch information
ShGKme committed Jan 27, 2024
1 parent c9cc3e7 commit be836c0
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 9 deletions.
2 changes: 1 addition & 1 deletion src/components/NcActions/NcActions.vue
Original file line number Diff line number Diff line change
Expand Up @@ -1448,7 +1448,7 @@ export default {
container: this.container,
popoverBaseClass: 'action-item__popper',
popupRole,
setReturnFocus: this.withFocusTrap ? this.$refs.menuButton?.$el : null,
noAutoReturnFocus: !this.withFocusTrap,
focusTrap: this.withFocusTrap,
},
// For some reason the popover component
Expand Down
4 changes: 2 additions & 2 deletions src/components/NcColorPicker/NcColorPicker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,8 @@ export default {
<template>
<div class="container1">
<NcButton @click="open = !open"> Click Me </NcButton>
<NcColorPicker :value="color" @input="updateColor" :shown.sync="open" v-slot="{ attrs }">
<div v-bind="attrs" :style="{'background-color': color}" class="color1" />
<NcColorPicker :value="color" @input="updateColor" :shown.sync="open">
<NcButton aria-label="Select color" :style="{'background-color': color}" class="color1" />
</NcColorPicker>
</div>
</template>
Expand Down
37 changes: 31 additions & 6 deletions src/components/NcPopover/NcPopover.vue
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,8 @@ import { createFocusTrap } from 'focus-trap'
import { getTrapStack } from '../../utils/focusTrap.js'
import NcPopoverTriggerProvider from './NcPopoverTriggerProvider.vue'
const buttonSelector = 'button, [role="button"], input[type="button"]'
export default {
name: 'NcPopover',
Expand Down Expand Up @@ -236,6 +238,15 @@ export default {
default: undefined,
type: [HTMLElement, SVGElement, String, Boolean],
},
/**
* When there is no setReturnFocus, NcPopover will try to return focus to the trigger button.
* Use this prop to disable this behavior.
*/
noAutoReturnFocus: {
type: Boolean,
default: false,
},
},
emits: [
Expand Down Expand Up @@ -279,11 +290,8 @@ export default {
*/
checkTriggerA11y() {
if (window.OC?.debug) {
// TODO: Vue 3: should be
// this.$refs.popover.$refs.popper.$refs.reference
const triggerContainer = this.$refs.popover.$refs.reference
const requiredTriggerButton = triggerContainer.querySelector('[aria-expanded][aria-haspopup]')
if (!requiredTriggerButton) {
const triggerButton = this.getPopoverTriggerButtonElement()
if (!triggerButton || !triggerButton.hasAttributes('aria-expanded', 'aria-haspopup')) {
Vue.util.warn('It looks like you are using a custom button as a <NcPopover> or other popover #trigger. If you are not using <NcButton> as a trigger, you need to bind attrs from the #trigger slot props to your custom button. See <NcPopover> docs for an example.')
}
}
Expand All @@ -296,6 +304,23 @@ export default {
return this.$refs.popover?.$refs.popperContent?.$el
},
/**
* @return {HTMLElement|undefined}
*/
getPopoverTriggerElement() {
// TODO: Vue 3: should be
// this.$refs.popover.$refs.popper.$refs.reference
return this.$refs.popover.$refs.reference
},
/**
* @return {HTMLElement|undefined}
*/
getPopoverTriggerButtonElement() {
const triggerContainer = this.getPopoverTriggerElement()
return triggerContainer?.querySelector(buttonSelector)
},
/**
* Add focus trap for accessibility.
*/
Expand All @@ -318,7 +343,7 @@ export default {
// Focus will be release when popover be hide
escapeDeactivates: false,
allowOutsideClick: true,
setReturnFocus: this.setReturnFocus,
setReturnFocus: this.setReturnFocus || (!this.noAutoReturnFocus && this.getPopoverTriggerButtonElement()),
trapStack: getTrapStack(),
})
this.$focusTrap.activate()
Expand Down

0 comments on commit be836c0

Please sign in to comment.