Skip to content

Commit dbb6818

Browse files
authored
fix(tooltip): avoid extra before open/close event emitting (#7422)
**Related Issue:** #7396 ## Summary Updates `TooltipManager` logic to avoid toggling hovered tooltips if they are the active ones.
1 parent 9a53b6a commit dbb6818

File tree

2 files changed

+98
-40
lines changed

2 files changed

+98
-40
lines changed

packages/calcite-components/src/components/tooltip/TooltipManager.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,11 @@ export default class TooltipManager {
215215
}
216216

217217
this.clearHoverCloseTimeout();
218+
219+
if (this.activeTooltip === this.hoveredTooltip) {
220+
return;
221+
}
222+
218223
this.closeActiveTooltip();
219224

220225
if (tooltip !== this.hoveredTooltip) {

packages/calcite-components/src/components/tooltip/tooltip.e2e.ts

Lines changed: 93 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { E2EPage, newE2EPage } from "@stencil/core/testing";
22
import { TOOLTIP_OPEN_DELAY_MS, TOOLTIP_CLOSE_DELAY_MS } from "../tooltip/resources";
33
import { accessible, defaults, hidden, floatingUIOwner, renders } from "../../tests/commonTests";
44
import { html } from "../../../support/formatting";
5-
import { GlobalTestProps } from "../../tests/utils";
5+
import { getElementXY, GlobalTestProps } from "../../tests/utils";
66

77
interface PointerMoveOptions {
88
delay: number;
@@ -677,59 +677,112 @@ describe("calcite-tooltip", () => {
677677
expect(await tooltip.isVisible()).toBe(true);
678678
});
679679

680-
it("should emit open and beforeOpen events", async () => {
681-
const page = await newE2EPage();
682-
await page.setContent(
683-
`<calcite-tooltip placement="auto" reference-element="ref">content</calcite-tooltip><div id="ref">referenceElement</div>`
684-
);
685-
const tooltip = await page.find("calcite-tooltip");
686-
687-
const openEvent = await tooltip.spyOnEvent("calciteTooltipOpen");
688-
const beforeOpenEvent = await tooltip.spyOnEvent("calciteTooltipBeforeOpen");
680+
describe("beforeOpen, open, beforeClose, close event emitting", () => {
681+
it("emits via prop", async () => {
682+
await assertEventEmitting({
683+
openTooltip: async (page) => {
684+
const tooltipBeforeOpenEvent = page.waitForEvent("calciteTooltipBeforeOpen");
685+
const tooltipOpenEvent = page.waitForEvent("calciteTooltipOpen");
686+
const tooltip = await page.find("calcite-tooltip");
689687

690-
expect(openEvent).toHaveReceivedEventTimes(0);
691-
expect(beforeOpenEvent).toHaveReceivedEventTimes(0);
688+
tooltip.setProperty("open", true);
689+
await page.waitForChanges();
692690

693-
const tooltipOpenEvent = page.waitForEvent("calciteTooltipOpen");
694-
const tooltipBeforeOpenEvent = page.waitForEvent("calciteTooltipBeforeOpen");
691+
await tooltipBeforeOpenEvent;
692+
await tooltipOpenEvent;
693+
},
694+
closeTooltip: async (page) => {
695+
const tooltipBeforeCloseEvent = page.waitForEvent("calciteTooltipBeforeClose");
696+
const tooltipCloseEvent = page.waitForEvent("calciteTooltipClose");
697+
const tooltip = await page.find("calcite-tooltip");
695698

696-
tooltip.setProperty("open", true);
697-
await page.waitForChanges();
699+
tooltip.setProperty("open", false);
700+
await page.waitForChanges();
698701

699-
await tooltipOpenEvent;
700-
await tooltipBeforeOpenEvent;
702+
await tooltipBeforeCloseEvent;
703+
await tooltipCloseEvent;
704+
},
705+
});
706+
});
701707

702-
expect(openEvent).toHaveReceivedEventTimes(1);
703-
expect(beforeOpenEvent).toHaveReceivedEventTimes(1);
704-
});
708+
it("emits via mouse", async () => {
709+
const moveOptions = { steps: 10 };
710+
const totalDelayFromMoveSteps = TOOLTIP_OPEN_DELAY_MS * moveOptions.steps;
711+
const xMoveOffset = 25;
705712

706-
it("should emit close and beforeClose events", async () => {
707-
const page = await newE2EPage();
708-
await page.setContent(
709-
`<calcite-tooltip placement="auto" reference-element="ref" open>content</calcite-tooltip><div id="ref">referenceElement</div>`
710-
);
713+
await assertEventEmitting({
714+
openTooltip: async (page: E2EPage) => {
715+
const [refElementX, refElementY] = await getElementXY(page, "#ref");
711716

712-
const tooltip = await page.find("calcite-tooltip");
717+
await page.mouse.move(0, 0, moveOptions);
718+
await page.mouse.move(refElementX, refElementY, moveOptions);
719+
await page.mouse.move(refElementX + xMoveOffset, refElementY, moveOptions);
720+
await page.waitForChanges();
713721

714-
const closeEvent = await tooltip.spyOnEvent("calciteTooltipClose");
715-
const beforeCloseEvent = await tooltip.spyOnEvent("calciteTooltipBeforeClose");
722+
await page.waitForTimeout(totalDelayFromMoveSteps);
723+
},
724+
closeTooltip: async (page: E2EPage) => {
725+
const [refElementX, refElementY] = await getElementXY(page, "#ref");
716726

717-
expect(closeEvent).toHaveReceivedEventTimes(0);
718-
expect(beforeCloseEvent).toHaveReceivedEventTimes(0);
727+
await page.mouse.move(refElementX + xMoveOffset, refElementY, moveOptions);
728+
await page.mouse.move(refElementX, refElementY, moveOptions);
729+
await page.mouse.move(0, 0, moveOptions);
730+
await page.waitForChanges();
719731

720-
const tooltipCloseEvent = page.waitForEvent("calciteTooltipClose");
721-
const tooltipBeforeCloseEvent = page.waitForEvent("calciteTooltipBeforeClose");
732+
await page.waitForTimeout(totalDelayFromMoveSteps);
733+
},
734+
});
735+
});
722736

723-
await page.evaluate(() => {
724-
const tooltip = document.querySelector("calcite-tooltip");
725-
tooltip.open = false;
737+
it("emits via keyboard", async () => {
738+
await assertEventEmitting({
739+
openTooltip: async (page) => {
740+
await page.keyboard.press("Tab");
741+
await page.waitForChanges();
742+
},
743+
closeTooltip: async (page) => {
744+
await page.keyboard.press("Tab");
745+
await page.waitForChanges();
746+
},
747+
});
726748
});
727749

728-
await tooltipBeforeCloseEvent;
729-
await tooltipCloseEvent;
750+
async function assertEventEmitting(params: {
751+
openTooltip: (page: E2EPage) => Promise<void>;
752+
closeTooltip: (page: E2EPage) => Promise<void>;
753+
}): Promise<void> {
754+
const page = await newE2EPage();
755+
await page.setContent(
756+
`<calcite-tooltip placement="auto" reference-element="ref">content</calcite-tooltip><button id="ref">referenceElement</button>`
757+
);
758+
const tooltip = await page.find("calcite-tooltip");
759+
760+
const beforeOpenEvent = await tooltip.spyOnEvent("calciteTooltipBeforeOpen");
761+
const openEvent = await tooltip.spyOnEvent("calciteTooltipOpen");
762+
const beforeCloseEvent = await tooltip.spyOnEvent("calciteTooltipBeforeClose");
763+
const closeEvent = await tooltip.spyOnEvent("calciteTooltipClose");
764+
765+
expect(beforeOpenEvent).toHaveReceivedEventTimes(0);
766+
expect(openEvent).toHaveReceivedEventTimes(0);
767+
expect(beforeCloseEvent).toHaveReceivedEventTimes(0);
768+
expect(closeEvent).toHaveReceivedEventTimes(0);
769+
770+
await params.openTooltip(page);
771+
await page.waitForChanges();
772+
773+
expect(beforeOpenEvent).toHaveReceivedEventTimes(1);
774+
expect(openEvent).toHaveReceivedEventTimes(1);
775+
expect(beforeCloseEvent).toHaveReceivedEventTimes(0);
776+
expect(closeEvent).toHaveReceivedEventTimes(0);
777+
778+
await params.closeTooltip(page);
779+
await page.waitForChanges();
730780

731-
expect(closeEvent).toHaveReceivedEventTimes(1);
732-
expect(beforeCloseEvent).toHaveReceivedEventTimes(1);
781+
expect(beforeOpenEvent).toHaveReceivedEventTimes(1);
782+
expect(openEvent).toHaveReceivedEventTimes(1);
783+
expect(beforeCloseEvent).toHaveReceivedEventTimes(1);
784+
expect(closeEvent).toHaveReceivedEventTimes(1);
785+
}
733786
});
734787

735788
it.skip("should open hovered tooltip while pointer is moving", async () => {

0 commit comments

Comments
 (0)