fix(arbitrary content): tabbing closes the dropdown when it's open

pull/2371/head
Gabriel Belgamo 2025-02-08 17:35:49 +00:00
rodzic e1fe8b0489
commit 223e33d345
2 zmienionych plików z 57 dodań i 1 usunięć

Wyświetl plik

@ -180,6 +180,12 @@ export default class SlDropdown extends ShoelaceElement {
return computeActiveElement(element?.shadowRoot?.activeElement);
};
const computeClosestContaining = (element: Element | null, tagName: string) => {
const closest = element?.closest(tagName);
if (closest !== null) return closest;
return computeClosestContaining((element?.getRootNode() as ShadowRoot).host, tagName);
};
// Tabbing outside of the containing element closes the panel
//
// If the dropdown is used within a shadow DOM, we need to obtain the activeElement within that shadowRoot,
@ -192,7 +198,8 @@ export default class SlDropdown extends ShoelaceElement {
if (
!this.containingElement ||
activeElement?.closest(this.containingElement.tagName.toLowerCase()) !== this.containingElement
computeClosestContaining(activeElement, this.containingElement.tagName.toLowerCase()) !==
this.containingElement
) {
this.hide();
}

Wyświetl plik

@ -402,4 +402,53 @@ describe('<sl-dropdown>', () => {
expect(dropdown.open).to.be.true;
});
});
describe('when arbitrary content is provided and the dropdown is opened', () => {
beforeEach(() => {
@customElement('custom-wrapper-arbitrary')
class WrapperArbitrary extends LitElement {
render() {
return html`<nested-dropdown-arbitrary></nested-dropdown-arbitrary>`;
}
}
// eslint-disable-next-line chai-friendly/no-unused-expressions
WrapperArbitrary;
@customElement('nested-dropdown-arbitrary')
class NestedDropdownArbitrary extends LitElement {
render() {
return html`
<sl-dropdown>
<sl-button slot="trigger" caret>Toggle</sl-button>
<ul>
<li><a href="/settings">Settings</a></li>
<li><a href="/profile">Profile</a></li>
</ul>
</sl-dropdown>
`;
}
}
// eslint-disable-next-line chai-friendly/no-unused-expressions
NestedDropdownArbitrary;
});
it('should remain open on tab key', async () => {
const el = await fixture<SlDropdown>(html`<custom-wrapper-arbitrary></custom-wrapper-arbitrary>`);
const dropdown = el
.shadowRoot!.querySelector('nested-dropdown-arbitrary')!
.shadowRoot!.querySelector('sl-dropdown')!;
const trigger = dropdown.querySelector('sl-button')!;
trigger.focus();
await dropdown.updateComplete;
await sendKeys({ press: 'Enter' });
await dropdown.updateComplete;
await sendKeys({ press: 'Tab' });
await dropdown.updateComplete;
expect(dropdown.open).to.be.true;
});
});
});