Skip to content

Commit

Permalink
Merge pull request #177 from Prestaul/176-shadow-in-button
Browse files Browse the repository at this point in the history
Ensure click events correctly cross out of ShadowDOM
  • Loading branch information
jgerigmeyer authored Feb 8, 2024
2 parents 1efb226 + 3457ec7 commit ef08b64
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 3 deletions.
10 changes: 10 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ <h1>Popover Attribute Polyfill</h1>
</ul>
</div>
</div>
<div id="popover12" popover>Popover 12</div>
<dialog popover>I'm a dialog!</dialog>
<div id="host"></div>

Expand Down Expand Up @@ -88,6 +89,15 @@ <h1>Popover Attribute Polyfill</h1>
<button popovertarget="notExist">Click to toggle nothing</button>
<button id="crossTreeToggle">Click to toggle shadowed Popover</button>
<button popovertargetaction="show" popovertarget="popover11">Menu</button>
<button popovertarget="popover12">
<span id="shadowInInvoker"></span>
</button>

<script type="module">
const host = document.getElementById('shadowInInvoker');
const shadowRoot = host.attachShadow({ mode: 'open' });
shadowRoot.innerHTML = `<span>Click to toggle Popover 12</span>`;
</script>
</div>
</body>
</html>
7 changes: 5 additions & 2 deletions src/popover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,15 +304,18 @@ export function apply() {

const handleInvokerActivation = (event: Event) => {
// Composed path allows us to find the target within shadowroots
const target = event.composedPath()[0] as HTMLElement;
const composedPath = event.composedPath() as HTMLElement[];
const target = composedPath[0];
if (!(target instanceof Element) || target?.shadowRoot) {
return;
}
const root = getRootNode(target);
if (!(root instanceof ShadowRoot || root instanceof Document)) {
return;
}
const invoker = target.closest('[popovertargetaction],[popovertarget]');
const invoker = composedPath.find(
(el) => el.matches && el.matches('[popovertargetaction],[popovertarget]'),
);
if (invoker) {
popoverTargetAttributeActivationBehavior(invoker as HTMLButtonElement);
event.preventDefault();
Expand Down
12 changes: 11 additions & 1 deletion tests/triggers.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ test("assign null to invoker's 'popoverTargetElement' property should remove its
).toBeNull();
});

test('clicking button#crossTreeToggle then button#crossTreeToggle twice should show and hide popover in a different tree scope', async ({
test('clicking button#crossTreeToggle should show then hide popover in a different tree scope', async ({
page,
}) => {
const popover = (await page.locator('#shadowedPopover')).nth(0);
Expand All @@ -224,3 +224,13 @@ test('clicking button#crossTreeToggle then button#crossTreeToggle twice should s
await page.click('button#crossTreeToggle');
await expect(popover).toBeHidden();
});

test('clicking #shadowInInvoker should show then hide popover', async ({
page,
}) => {
const popover = (await page.locator('#popover12')).nth(0);
await page.click('#shadowInInvoker');
await expect(popover).toBeVisible();
await page.click('#shadowInInvoker');
await expect(popover).toBeHidden();
});

0 comments on commit ef08b64

Please sign in to comment.