From f2d9b8e232905539a50a6f8a1b5690356b4955ff Mon Sep 17 00:00:00 2001 From: Thijs Louisse Date: Mon, 12 Apr 2021 23:23:56 +0200 Subject: [PATCH] fix(overlays): only focus controlled elements after hide --- .changeset/loud-rocks-teach.md | 5 +++++ packages/overlays/src/OverlayController.js | 16 ++++++++++------ .../overlays/test/OverlayController.test.js | 19 +++++++++++++++++++ 3 files changed, 34 insertions(+), 6 deletions(-) create mode 100644 .changeset/loud-rocks-teach.md diff --git a/.changeset/loud-rocks-teach.md b/.changeset/loud-rocks-teach.md new file mode 100644 index 000000000..b2624195e --- /dev/null +++ b/.changeset/loud-rocks-teach.md @@ -0,0 +1,5 @@ +--- +'@lion/overlays': patch +--- + +only focus elements after hide when OverlayController has ownership diff --git a/packages/overlays/src/OverlayController.js b/packages/overlays/src/OverlayController.js index df74b416b..bddab5239 100644 --- a/packages/overlays/src/OverlayController.js +++ b/packages/overlays/src/OverlayController.js @@ -907,15 +907,19 @@ export class OverlayController extends EventTargetShim { /** @protected */ _restoreFocus() { + const { activeElement } = /** @type {* & ShadowRoot} */ (this + .__contentWrapperNode).getRootNode(); // We only are allowed to move focus if we (still) 'own' it. // Otherwise we assume the 'outside world' has, purposefully, taken over - if (this.elementToFocusAfterHide) { - this.elementToFocusAfterHide.focus(); - } else if ( - document.activeElement && - this.__contentWrapperNode?.contains(document.activeElement) + if ( + activeElement && + /** @type {HTMLElement} */ (this.__contentWrapperNode).contains(activeElement) ) { - /** @type {HTMLElement} */ (document.activeElement).blur(); + if (this.elementToFocusAfterHide) { + this.elementToFocusAfterHide.focus(); + } else { + activeElement.blur(); + } } } diff --git a/packages/overlays/test/OverlayController.test.js b/packages/overlays/test/OverlayController.test.js index 927e98815..47c0e3dec 100644 --- a/packages/overlays/test/OverlayController.test.js +++ b/packages/overlays/test/OverlayController.test.js @@ -741,6 +741,25 @@ describe('OverlayController', () => { 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('')); + const outsideButton = /** @type {HTMLButtonElement} */ (await fixture('')); + const contentNode = /** @type {HTMLElement} */ (await fixture('
/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 () => { const input = /** @type {HTMLElement} */ (await fixture('')); const contentNode = /** @type {HTMLElement} */ (await fixture(