From cb60ea50ac07456075e5b3c3f019b74081efab57 Mon Sep 17 00:00:00 2001 From: johanrd Date: Sat, 5 Dec 2020 11:21:38 +0100 Subject: [PATCH] Accessibility: Do not hide popover when focusing an element within the popover Fixes an accessibility issue where the popover was hidden when an element within the popover was navigated to by keyboard. The fix checks if the relatedTarget of the 'focusout' event is inside inside the popover. If true, the popover is not hidden. --- addon/components/ember-popover.js | 8 ++++---- addon/components/ember-tooltip-base.js | 17 +++++++++++++++-- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/addon/components/ember-popover.js b/addon/components/ember-popover.js index 526b23e8..5e939d76 100644 --- a/addon/components/ember-popover.js +++ b/addon/components/ember-popover.js @@ -57,8 +57,8 @@ export default EmberTooltipBase.extend({ this.set('_isMouseInside', false); }); - this._addEventListener('focusout', () => { - if (!this.get('_isMouseInside') && this.get('hideOn') !== 'none') { + this._addEventListener('focusout', (event) => { + if (!this.get('_isMouseInside') && this.get('hideOn') !== 'none' && !this._isTargetReceivingFocusInsidePopover(event)) { this.hide(); } }); @@ -88,8 +88,8 @@ export default EmberTooltipBase.extend({ } }, popover); - this._addEventListener('focusout', () => { - if (!this.get('_isMouseInside') && this.get('isShown') && this.get('hideOn') !== 'none') { + this._addEventListener('focusout', (event) => { + if (!this.get('_isMouseInside') && this.get('isShown') && this.get('hideOn') !== 'none' && !this._isTargetReceivingFocusInsidePopover(event)) { this.hide(); } }, popover); diff --git a/addon/components/ember-tooltip-base.js b/addon/components/ember-tooltip-base.js index bf448c4a..51116c7f 100644 --- a/addon/components/ember-tooltip-base.js +++ b/addon/components/ember-tooltip-base.js @@ -221,6 +221,17 @@ export default Component.extend({ return inTestingMode ? 0 : this.animationDuration; }), + + /** + * Check if the EventTarget receiving focus is inside the popover (e.g. by keyboard navigation) + * @param {FocusEvent} event - event.relatedTarget is an EventTarget receiving focus (if any) + * @returns {boolean} true if the focus shifts to an element that is contained within the popover + */ + + _isTargetReceivingFocusInsidePopover(event) { + return !!this.get('_tooltip.popperInstance.popper')?.contains(event.relatedTarget) + }, + init() { this._super(...arguments); this.set('_tooltipEvents', []); @@ -326,8 +337,10 @@ export default Component.extend({ }); } - this._addEventListener('focusout', () => { - this.hide(); + this._addEventListener('focusout', (event) => { + if (!this._isTargetReceivingFocusInsidePopover(event)) { + this.hide(); + } }); }