fix(overlays): only focus controlled elements after hide

This commit is contained in:
Thijs Louisse 2021-04-12 23:23:56 +02:00
parent d65ffd3c04
commit f2d9b8e232
3 changed files with 34 additions and 6 deletions

View file

@ -0,0 +1,5 @@
---
'@lion/overlays': patch
---
only focus elements after hide when OverlayController has ownership

View file

@ -907,15 +907,19 @@ export class OverlayController extends EventTargetShim {
/** @protected */ /** @protected */
_restoreFocus() { _restoreFocus() {
const { activeElement } = /** @type {* & ShadowRoot} */ (this
.__contentWrapperNode).getRootNode();
// We only are allowed to move focus if we (still) 'own' it. // We only are allowed to move focus if we (still) 'own' it.
// Otherwise we assume the 'outside world' has, purposefully, taken over // Otherwise we assume the 'outside world' has, purposefully, taken over
if (this.elementToFocusAfterHide) { if (
this.elementToFocusAfterHide.focus(); activeElement &&
} else if ( /** @type {HTMLElement} */ (this.__contentWrapperNode).contains(activeElement)
document.activeElement &&
this.__contentWrapperNode?.contains(document.activeElement)
) { ) {
/** @type {HTMLElement} */ (document.activeElement).blur(); if (this.elementToFocusAfterHide) {
this.elementToFocusAfterHide.focus();
} else {
activeElement.blur();
}
} }
} }

View file

@ -741,6 +741,25 @@ describe('OverlayController', () => {
expect(document.activeElement).to.equal(input); expect(document.activeElement).to.equal(input);
}); });
it(`only sets focus when outside world didn't take over already`, async () => {
const input = /** @type {HTMLElement} */ (await fixture('<input />'));
const outsideButton = /** @type {HTMLButtonElement} */ (await fixture('<button></button>'));
const contentNode = /** @type {HTMLElement} */ (await fixture('<div>/div>'));
const ctrl = new OverlayController({
...withGlobalTestConfig(),
elementToFocusAfterHide: input,
contentNode,
});
await ctrl.show();
// an outside element has taken over focus
outsideButton.focus();
expect(document.activeElement).to.equal(outsideButton);
await ctrl.hide();
expect(document.activeElement).to.equal(outsideButton);
});
it('allows to set elementToFocusAfterHide on show', async () => { it('allows to set elementToFocusAfterHide on show', async () => {
const input = /** @type {HTMLElement} */ (await fixture('<input />')); const input = /** @type {HTMLElement} */ (await fixture('<input />'));
const contentNode = /** @type {HTMLElement} */ (await fixture( const contentNode = /** @type {HTMLElement} */ (await fixture(