Skip to content

Commit

Permalink
fix(tooltip, popover): honor prevented events (#11278)
Browse files Browse the repository at this point in the history
**Related Issue:** #11244

## Summary

- updates tooltip and popover to take no action on prevented events
- adds tests
- This allows users to prevent an event instead of stopping propagation
on it.
  • Loading branch information
driskull authored Jan 15, 2025
1 parent d35d44a commit 68f0723
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export default class PopoverManager {
};

private clickHandler = (event: PointerEvent): void => {
if (isKeyboardTriggeredClick(event)) {
if (isKeyboardTriggeredClick(event) || event.defaultPrevented) {
return;
}

Expand Down
29 changes: 29 additions & 0 deletions packages/calcite-components/src/components/popover/popover.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,35 @@ describe("calcite-popover", () => {
expect(await popover.getProperty("open")).toBe(true);
});

it("should not open popovers if event is prevented", async () => {
const page = await newE2EPage();

await page.setContent(html`
<calcite-popover reference-element="ref">Content</calcite-popover>
<div id="ref">Button</div>
`);

await page.waitForChanges();

const popover = await page.find("calcite-popover");

expect(await popover.getProperty("open")).toBe(false);

await page.$eval("#ref", (ref) => {
ref.addEventListener("click", (event) => {
event.preventDefault();
});
});

const referenceElement = await page.find("#ref");

await referenceElement.click();

await page.waitForChanges();

expect(await popover.getProperty("open")).toBe(false);
});

it("should not be visible if reference is hidden", async () => {
const page = await newE2EPage();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ export default class TooltipManager {
};

private pointerMoveHandler = (event: PointerEvent): void => {
if (event.defaultPrevented) {
return;
}

const composedPath = event.composedPath();
const { activeTooltip } = this;

Expand Down Expand Up @@ -129,6 +133,10 @@ export default class TooltipManager {
}

private clickHandler = (event: Event): void => {
if (event.defaultPrevented) {
return;
}

this.clickedTooltip = null;
const composedPath = event.composedPath();
const tooltip = this.queryTooltip(composedPath);
Expand Down Expand Up @@ -160,6 +168,10 @@ export default class TooltipManager {
};

private focusInHandler = (event: FocusEvent): void => {
if (event.defaultPrevented) {
return;
}

const composedPath = event.composedPath();
const tooltip = this.queryTooltip(composedPath);

Expand Down
114 changes: 114 additions & 0 deletions packages/calcite-components/src/components/tooltip/tooltip.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,34 @@ describe("calcite-tooltip", () => {
expect(await positionContainer.isVisible()).toBe(true);
});

it("should not open when hover event is prevented", async () => {
const page = await newE2EPage();

await page.setContent(
`<calcite-tooltip reference-element="ref">content</calcite-tooltip><div id="ref">referenceElement</div>`,
);

await page.waitForChanges();

const positionContainer = await page.find(`calcite-tooltip >>> .${CSS.positionContainer}`);

expect(await positionContainer.isVisible()).toBe(false);

await page.$eval("#ref", (ref) => {
ref.addEventListener("pointermove", (event) => {
event.preventDefault();
});
});

const ref = await page.find("#ref");

await ref.hover();

await page.waitForTimeout(TOOLTIP_OPEN_DELAY_MS);

expect(await positionContainer.isVisible()).toBe(false);
});

it("should honor hover interaction with span inside", async () => {
const page = await newE2EPage();

Expand Down Expand Up @@ -426,6 +454,34 @@ describe("calcite-tooltip", () => {
expect(await tooltip.getProperty("open")).toBe(false);
});

it("should not open if focus event is prevented", async () => {
const page = await newE2EPage();

await page.setContent(html`
<button id="test">test</button>
<calcite-tooltip reference-element="ref">Content</calcite-tooltip>
<button id="ref">Button</button>
`);

await page.waitForChanges();

const tooltip = await page.find("calcite-tooltip");

expect(await tooltip.getProperty("open")).toBe(false);

await page.$eval("#ref", (ref) => {
ref.addEventListener("focusin", (event) => {
event.preventDefault();
});

ref.dispatchEvent(new FocusEvent("focusin", { bubbles: true, cancelable: true }));
});

await page.waitForChanges();

expect(await tooltip.getProperty("open")).toBe(false);
});

it("should handle mouse events", async () => {
const page = await newE2EPage();

Expand Down Expand Up @@ -547,6 +603,45 @@ describe("calcite-tooltip", () => {
await assertEscapeKeyCanceled(page, true);
});

it("should not close with ESC key if event is prevented", async () => {
const page = await newE2EPage();

await page.setContent(html`
<calcite-tooltip reference-element="ref">Content</calcite-tooltip>
<button id="ref">Button</button>
`);

await page.waitForChanges();

const tooltip = await page.find("calcite-tooltip");

expect(await tooltip.getProperty("open")).toBe(false);

const referenceElement = await page.find("#ref");

await referenceElement.focus();

await referenceElement.hover();

await page.waitForTimeout(TOOLTIP_OPEN_DELAY_MS);

await page.waitForChanges();

expect(await tooltip.getProperty("open")).toBe(true);

await page.evaluate(() => {
document.body.addEventListener("keydown", (event) => {
if (event.key === "Escape") {
event.preventDefault();
}
});
});

await dispatchKeydownEvent(page, "#ref", "Escape");

expect(await tooltip.getProperty("open")).toBe(true);
});

it("should only open the last focused tooltip", async () => {
const page = await newE2EPage();

Expand Down Expand Up @@ -1175,6 +1270,25 @@ describe("calcite-tooltip", () => {
expect(await tooltip.getProperty("open")).toBe(false);
});

it("should not open when click event is prevented", async () => {
const page = await newE2EPage();
await page.setContent(pageContent);
await skipAnimations(page);
await page.waitForChanges();
const tooltip = await page.find("calcite-tooltip");

await page.$eval("#ref", (ref) => {
ref.addEventListener("click", (event) => {
event.preventDefault();
});

ref.dispatchEvent(new MouseEvent("click", { bubbles: true, cancelable: true }));
});

await page.waitForChanges();
expect(await tooltip.getProperty("open")).toBe(false);
});

it("should work when focusing on a reference element first", async () => {
const page = await newE2EPage();
await page.setContent(pageContent);
Expand Down

0 comments on commit 68f0723

Please sign in to comment.