fix(overlays): only focus controlled elements after hide
This commit is contained in:
parent
d65ffd3c04
commit
f2d9b8e232
3 changed files with 34 additions and 6 deletions
5
.changeset/loud-rocks-teach.md
Normal file
5
.changeset/loud-rocks-teach.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'@lion/overlays': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
only focus elements after hide when OverlayController has ownership
|
||||||
|
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue