Skip to content

Commit

Permalink
fix(tooltip): allow focusing on a reference element and then clicking…
Browse files Browse the repository at this point in the history
… on a tooltip (#9878)

**Related Issue:** #9840

## Summary

- allows clicking on a tooltip while a referenceElement is focused
- adds tests
  • Loading branch information
driskull authored and github-actions[bot] committed Jul 30, 2024
1 parent 29a016e commit dfca2d4
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -140,38 +140,45 @@ export default class TooltipManager {
this.toggleTooltip(tooltip, true);
};

private focusInHandler = (event: FocusEvent): void => {
this.queryFocusedTooltip(event, true);
private blurHandler = (): void => {
this.closeActiveTooltip();
};

private focusOutHandler = (event: FocusEvent): void => {
this.queryFocusedTooltip(event, false);
private focusInHandler = (event: FocusEvent): void => {
const composedPath = event.composedPath();
const tooltip = this.queryTooltip(composedPath);

this.closeTooltipIfNotActive(tooltip);

if (!tooltip) {
return;
}

this.toggleFocusedTooltip(tooltip, true);
};

private addShadowListeners(shadowRoot: ShadowRoot): void {
shadowRoot.addEventListener("focusin", this.focusInHandler, { capture: true });
shadowRoot.addEventListener("focusout", this.focusOutHandler, { capture: true });
}

private removeShadowListeners(shadowRoot: ShadowRoot): void {
shadowRoot.removeEventListener("focusin", this.focusInHandler, { capture: true });
shadowRoot.removeEventListener("focusout", this.focusOutHandler, { capture: true });
}

private addListeners(): void {
window.addEventListener("keydown", this.keyDownHandler, { capture: true });
window.addEventListener("pointermove", this.pointerMoveHandler, { capture: true });
window.addEventListener("click", this.clickHandler, { capture: true });
window.addEventListener("focusin", this.focusInHandler, { capture: true });
window.addEventListener("focusout", this.focusOutHandler, { capture: true });
window.addEventListener("blur", this.blurHandler);
}

private removeListeners(): void {
window.removeEventListener("keydown", this.keyDownHandler, { capture: true });
window.removeEventListener("pointermove", this.pointerMoveHandler, { capture: true });
window.removeEventListener("click", this.clickHandler, { capture: true });
window.removeEventListener("focusin", this.focusInHandler, { capture: true });
window.removeEventListener("focusout", this.focusOutHandler, { capture: true });
window.removeEventListener("blur", this.blurHandler);
}

private clearHoverOpenTimeout(): void {
Expand Down Expand Up @@ -242,23 +249,11 @@ export default class TooltipManager {
}, TOOLTIP_CLOSE_DELAY_MS);
};

private queryFocusedTooltip(event: FocusEvent, open: boolean): void {
const composedPath = event.composedPath();
const tooltip = this.queryTooltip(composedPath);

this.closeTooltipIfNotActive(tooltip);

if (!tooltip) {
return;
}

this.toggleFocusedTooltip(tooltip, open);
}

private registerShadowRoot(shadowRoot: ShadowRoot): void {
const { registeredShadowRootCounts } = this;

const newCount = (registeredShadowRootCounts.get(shadowRoot) ?? 0) + 1;
const count = registeredShadowRootCounts.get(shadowRoot);
const newCount = Math.min((typeof count === "number" ? count : 0) + 1, 1);

if (newCount === 1) {
this.addShadowListeners(shadowRoot);
Expand All @@ -270,7 +265,8 @@ export default class TooltipManager {
private unregisterShadowRoot(shadowRoot: ShadowRoot): void {
const { registeredShadowRootCounts } = this;

const newCount = registeredShadowRootCounts.get(shadowRoot) - 1;
const count = registeredShadowRootCounts.get(shadowRoot);
const newCount = Math.max((typeof count === "number" ? count : 1) - 1, 0);

if (newCount === 0) {
this.removeShadowListeners(shadowRoot);
Expand Down
51 changes: 51 additions & 0 deletions packages/calcite-components/src/components/tooltip/tooltip.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1108,4 +1108,55 @@ describe("calcite-tooltip", () => {
expect(await tooltip1.getProperty("open")).toBe(false);
expect(await tooltip2.getProperty("open")).toBe(true);
});

describe("allows clicking on an open tooltip", () => {
const pageContent = html`
<calcite-tooltip placement="auto" reference-element="ref">content</calcite-tooltip>
<button id="ref">referenceElement</button>
<button id="other">other</button>
`;

it("should work when clicking on a reference element first", async () => {
const page = await newE2EPage();
await page.setContent(pageContent);
await page.waitForChanges();
const tooltip = await page.find("calcite-tooltip");
const referenceElement = await page.find("#ref");

await referenceElement.click();
await page.waitForChanges();
expect(await tooltip.getProperty("open")).toBe(true);

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

await page.$eval("#other", (el: HTMLElement) => {
el.dispatchEvent(new MouseEvent("click", { cancelable: true, bubbles: 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);
await page.waitForChanges();
const tooltip = await page.find("calcite-tooltip");
const referenceElement = await page.find("#ref");

await referenceElement.focus();
await page.waitForChanges();
expect(await tooltip.getProperty("open")).toBe(true);

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

const other = await page.find("#other");
await other.focus();
await page.waitForChanges();
expect(await tooltip.getProperty("open")).toBe(false);
});
});
});

0 comments on commit dfca2d4

Please sign in to comment.