Skip to content

Commit 77459fb

Browse files
authored
feat(tooltip): support touch events (#9487)
**Related Issue:** #9273 ## Summary - support tap/touch events for tooltip - cleanup - removed private vars for hoveredTooltip, clickedTooltip to simplify things - add test
1 parent 1e21ca3 commit 77459fb

File tree

2 files changed

+82
-49
lines changed

2 files changed

+82
-49
lines changed

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

Lines changed: 43 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,6 @@ export default class TooltipManager {
1818

1919
private hoverCloseTimeout: number = null;
2020

21-
private hoveredTooltip: HTMLCalciteTooltipElement = null;
22-
23-
private clickedTooltip: HTMLCalciteTooltipElement = null;
24-
2521
private activeTooltip: HTMLCalciteTooltipElement = null;
2622

2723
private registeredElementCount = 0;
@@ -96,38 +92,52 @@ export default class TooltipManager {
9692
private pointerMoveHandler = (event: PointerEvent): void => {
9793
const composedPath = event.composedPath();
9894
const { activeTooltip } = this;
99-
const hoveringActiveTooltip = activeTooltip?.open && composedPath.includes(activeTooltip);
100-
101-
if (hoveringActiveTooltip) {
102-
this.clearHoverTimeout();
103-
return;
104-
}
10595

10696
const tooltip = this.queryTooltip(composedPath);
107-
this.hoveredTooltip = tooltip;
10897

109-
if (this.isClosableClickedTooltip(tooltip)) {
98+
if (this.pathHasOpenTooltip(tooltip, composedPath)) {
99+
this.clearHoverTimeout();
110100
return;
111101
}
112102

113-
this.clickedTooltip = null;
114-
115103
if (tooltip) {
116104
this.openHoveredTooltip(tooltip);
117-
} else if (activeTooltip) {
105+
} else if (activeTooltip?.open) {
118106
this.closeHoveredTooltip();
119107
}
120108
};
121109

122-
private clickHandler = (event: PointerEvent): void => {
123-
const clickedTooltip = this.queryTooltip(event.composedPath());
110+
private pathHasOpenTooltip(tooltip: HTMLCalciteTooltipElement, composedPath: EventTarget[]): boolean {
111+
const { activeTooltip } = this;
124112

125-
this.clickedTooltip = clickedTooltip;
113+
return (
114+
(activeTooltip?.open && composedPath.includes(activeTooltip)) || (tooltip?.open && composedPath.includes(tooltip))
115+
);
116+
}
126117

127-
if (clickedTooltip?.closeOnClick) {
128-
this.toggleTooltip(clickedTooltip, false);
118+
private clickHandler = (event: Event): void => {
119+
const composedPath = event.composedPath();
120+
const tooltip = this.queryTooltip(composedPath);
121+
122+
if (this.pathHasOpenTooltip(tooltip, composedPath)) {
129123
this.clearHoverTimeout();
124+
return;
130125
}
126+
127+
this.closeActiveTooltip();
128+
129+
if (!tooltip) {
130+
return;
131+
}
132+
133+
this.clearHoverTimeout();
134+
135+
if (tooltip.closeOnClick) {
136+
this.toggleTooltip(tooltip, false);
137+
return;
138+
}
139+
140+
this.toggleTooltip(tooltip, true);
131141
};
132142

133143
private focusInHandler = (event: FocusEvent): void => {
@@ -179,6 +189,12 @@ export default class TooltipManager {
179189
this.clearHoverCloseTimeout();
180190
}
181191

192+
private closeTooltipIfNotActive(tooltip: HTMLCalciteTooltipElement): void {
193+
if (this.activeTooltip !== tooltip) {
194+
this.closeActiveTooltip();
195+
}
196+
}
197+
182198
private closeActiveTooltip(): void {
183199
const { activeTooltip } = this;
184200

@@ -188,8 +204,6 @@ export default class TooltipManager {
188204
}
189205

190206
private toggleFocusedTooltip(tooltip: HTMLCalciteTooltipElement, open: boolean): void {
191-
this.closeActiveTooltip();
192-
193207
if (open) {
194208
this.clearHoverTimeout();
195209
}
@@ -211,20 +225,10 @@ export default class TooltipManager {
211225
}
212226

213227
this.clearHoverCloseTimeout();
214-
215-
if (this.activeTooltip === this.hoveredTooltip) {
216-
return;
217-
}
218-
219-
this.closeActiveTooltip();
220-
221-
if (tooltip !== this.hoveredTooltip) {
222-
return;
223-
}
224-
228+
this.closeTooltipIfNotActive(tooltip);
225229
this.toggleTooltip(tooltip, true);
226230
},
227-
this.activeTooltip ? 0 : TOOLTIP_OPEN_DELAY_MS,
231+
this.activeTooltip?.open ? 0 : TOOLTIP_OPEN_DELAY_MS,
228232
);
229233
};
230234

@@ -239,19 +243,18 @@ export default class TooltipManager {
239243
};
240244

241245
private queryFocusedTooltip(event: FocusEvent, open: boolean): void {
242-
const tooltip = this.queryTooltip(event.composedPath());
246+
const composedPath = event.composedPath();
247+
const tooltip = this.queryTooltip(composedPath);
248+
249+
this.closeTooltipIfNotActive(tooltip);
243250

244-
if (!tooltip || this.isClosableClickedTooltip(tooltip)) {
251+
if (!tooltip) {
245252
return;
246253
}
247254

248255
this.toggleFocusedTooltip(tooltip, open);
249256
}
250257

251-
private isClosableClickedTooltip(tooltip: HTMLCalciteTooltipElement): boolean {
252-
return tooltip?.closeOnClick && tooltip === this.clickedTooltip;
253-
}
254-
255258
private registerShadowRoot(shadowRoot: ShadowRoot): void {
256259
const { registeredShadowRootCounts } = this;
257260

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

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ describe("calcite-tooltip", () => {
371371
expect(await tooltip.getProperty("open")).toBe(false);
372372
});
373373

374-
it("should not open tooltip when clicked", async () => {
374+
it("should handle mouse events", async () => {
375375
const page = await newE2EPage();
376376

377377
await page.setContent(html`
@@ -388,7 +388,37 @@ describe("calcite-tooltip", () => {
388388

389389
await page.evaluate(() => {
390390
const ref = document.getElementById("ref");
391-
ref.click();
391+
const event1 = new MouseEvent("click", {
392+
cancelable: true,
393+
bubbles: true,
394+
});
395+
ref.dispatchEvent(event1);
396+
});
397+
398+
await page.waitForChanges();
399+
400+
expect(await tooltip.getProperty("open")).toBe(true);
401+
402+
await page.evaluate(() => {
403+
const ref = document.getElementById("ref");
404+
const event1 = new MouseEvent("click", {
405+
cancelable: true,
406+
bubbles: true,
407+
});
408+
ref.dispatchEvent(event1);
409+
});
410+
411+
await page.waitForChanges();
412+
413+
expect(await tooltip.getProperty("open")).toBe(true);
414+
415+
await page.evaluate(() => {
416+
const ref = document.getElementById("test");
417+
const event1 = new MouseEvent("click", {
418+
cancelable: true,
419+
bubbles: true,
420+
});
421+
ref.dispatchEvent(event1);
392422
});
393423

394424
await page.waitForChanges();
@@ -516,7 +546,7 @@ describe("calcite-tooltip", () => {
516546
expect(await hoverTip.getProperty("open")).toBe(false);
517547

518548
await page.$eval("#hoverRef", (el: HTMLElement) => {
519-
el.dispatchEvent(new Event("pointermove"));
549+
el.dispatchEvent(new PointerEvent("pointermove"));
520550
});
521551

522552
await page.waitForTimeout(TOOLTIP_OPEN_DELAY_MS);
@@ -572,7 +602,7 @@ describe("calcite-tooltip", () => {
572602
expect(await hoverTip.getProperty("open")).toBe(false);
573603

574604
await page.$eval("#hoverRef", (el: HTMLElement) => {
575-
el.dispatchEvent(new Event("pointermove"));
605+
el.dispatchEvent(new PointerEvent("pointermove"));
576606
});
577607

578608
await page.waitForTimeout(TOOLTIP_OPEN_DELAY_MS);
@@ -911,7 +941,7 @@ describe("calcite-tooltip", () => {
911941
const { delay, selector } = pointerMoves[i];
912942
await page.waitForTimeout(delay);
913943
await page.$eval(selector, (el: HTMLElement) => {
914-
el.dispatchEvent(new Event("pointermove"));
944+
el.dispatchEvent(new PointerEvent("pointermove"));
915945
});
916946

917947
expect(await tooltip.getProperty(pointerMoves[i].property)).toBe(pointerMoves[i].value);
@@ -970,7 +1000,7 @@ describe("calcite-tooltip", () => {
9701000
const { delay, selector } = pointerMoves[i];
9711001
await page.waitForTimeout(delay);
9721002
await page.$eval(selector, (el: HTMLElement) => {
973-
el.dispatchEvent(new Event("pointermove"));
1003+
el.dispatchEvent(new PointerEvent("pointermove"));
9741004
});
9751005

9761006
expect(await tooltip.getProperty(pointerMoves[i].property)).toBe(pointerMoves[i].value);
@@ -1029,7 +1059,7 @@ describe("calcite-tooltip", () => {
10291059
.querySelector("shadow-component-b")
10301060
.shadowRoot.querySelector("shadow-component-a")
10311061
.shadowRoot.querySelector("button");
1032-
referenceElement.dispatchEvent(new Event("focusin"));
1062+
referenceElement.dispatchEvent(new FocusEvent("focusin"));
10331063
});
10341064
}
10351065

@@ -1061,7 +1091,7 @@ describe("calcite-tooltip", () => {
10611091
expect(await tooltip2.getProperty("open")).toBe(false);
10621092

10631093
await page.$eval("#ref1", (el: HTMLElement) => {
1064-
el.dispatchEvent(new Event("pointermove"));
1094+
el.dispatchEvent(new PointerEvent("pointermove"));
10651095
});
10661096
await page.waitForTimeout(TOOLTIP_OPEN_DELAY_MS);
10671097
await page.waitForChanges();
@@ -1070,7 +1100,7 @@ describe("calcite-tooltip", () => {
10701100
expect(await tooltip2.getProperty("open")).toBe(false);
10711101

10721102
await page.$eval("#ref2", (el: HTMLElement) => {
1073-
el.dispatchEvent(new Event("pointermove"));
1103+
el.dispatchEvent(new PointerEvent("pointermove"));
10741104
});
10751105
await page.waitForTimeout(0);
10761106
await page.waitForChanges();

0 commit comments

Comments
 (0)