diff --git a/packages/calcite-components/src/components/tooltip/TooltipManager.ts b/packages/calcite-components/src/components/tooltip/TooltipManager.ts
index 4c6da729fac..5ee59a8df6b 100644
--- a/packages/calcite-components/src/components/tooltip/TooltipManager.ts
+++ b/packages/calcite-components/src/components/tooltip/TooltipManager.ts
@@ -140,22 +140,29 @@ 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 {
@@ -163,7 +170,7 @@ export default class TooltipManager {
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 {
@@ -171,7 +178,7 @@ export default class TooltipManager {
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 {
@@ -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);
@@ -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);
diff --git a/packages/calcite-components/src/components/tooltip/tooltip.e2e.ts b/packages/calcite-components/src/components/tooltip/tooltip.e2e.ts
index 446be26d13d..a26d919bd90 100644
--- a/packages/calcite-components/src/components/tooltip/tooltip.e2e.ts
+++ b/packages/calcite-components/src/components/tooltip/tooltip.e2e.ts
@@ -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`
+ content
+
+
+ `;
+
+ 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);
+ });
+ });
});