fix nested dialog focus

This commit is contained in:
konnorrogers
2023-11-09 13:33:20 -05:00
parent 5221419816
commit 5cb76857c7
2 changed files with 47 additions and 1 deletions

View File

@@ -63,11 +63,13 @@ export default class Modal {
}
private handleFocusIn = () => {
if (!this.isActive()) return
this.checkFocus();
};
private handleKeyDown = (event: KeyboardEvent) => {
if (event.key !== 'Tab' || this.isExternalActivated) return;
if (!this.isActive()) return
if (event.shiftKey) {
this.tabDirection = 'backward';

View File

@@ -1,9 +1,11 @@
import { elementUpdated, expect, fixture } from '@open-wc/testing';
import { aTimeout, elementUpdated, expect, fixture } from '@open-wc/testing';
import '../../dist/shoelace.js';
import { activeElements, getDeepestActiveElement } from './active-elements.js';
import { html } from 'lit';
import { sendKeys } from '@web/test-runner-commands';
import { SlDialog } from '../../dist/shoelace.js';
import { clickOnElement } from './test.js';
async function holdShiftKey(callback: () => Promise<void>) {
await sendKeys({ down: 'Shift' });
@@ -174,3 +176,45 @@ it('Should account for when focus is changed from outside sources (like clicking
await holdShiftKey(async () => await sendKeys({ press: tabKey }));
expect(activeElementsArray()).to.include(closeButton);
});
// https://github.com/shoelace-style/shoelace/issues/1710
it("Should respect nested modal instances", async () => {
const dialogOne = () => document.querySelector("#dialog-1") as SlDialog
const dialogTwo = () => document.querySelector("#dialog-2") as SlDialog
await fixture(html`
<div>
<sl-button id="open-dialog-1" @click=${() => dialogOne().show()}></sl-button>
<sl-dialog id="dialog-1" label="Dialog 1">
<sl-button @click=${() => dialogTwo().show()} id="open-dialog-2">Open Dialog 2</sl-button>
<sl-button slot="footer" variant="primary">Close</sl-button>
</sl-dialog>
<sl-dialog id="dialog-2" label="Dialog 2">
<sl-input
id="focus-1"
autofocus=""
placeholder="I will have focus when the dialog is opened"
></sl-input>
<sl-input id="focus-2" placeholder="Second input"></sl-input>
<sl-button slot="footer" variant="primary" class="close-2">Close</sl-button>
</sl-dialog>
</div>
`)
const firstFocusedEl = document.querySelector("#focus-1")
const secondFocusedEl = document.querySelector("#focus-2")
// So we can trigger auto-focus stuff
await clickOnElement(document.querySelector("#open-dialog-1") as Element)
// These clicks need a ~10ms timeout. Not sure why, if we don't do this, tests get flaky.
await aTimeout(100)
await clickOnElement(document.querySelector("#open-dialog-2") as Element)
await aTimeout(100)
expect(activeElementsArray()).to.include(firstFocusedEl)
await sendKeys({ press: tabKey })
expect(activeElementsArray()).to.include(secondFocusedEl)
})