diff --git a/packages/calcite-components/src/components/popover/PopoverManager.ts b/packages/calcite-components/src/components/popover/PopoverManager.ts
index 74cc669c574..a295cf325e6 100644
--- a/packages/calcite-components/src/components/popover/PopoverManager.ts
+++ b/packages/calcite-components/src/components/popover/PopoverManager.ts
@@ -1,9 +1,26 @@
// @ts-strict-ignore
import { ReferenceElement } from "../../utils/floating-ui";
import { isActivationKey } from "../../utils/key";
-import { isKeyboardTriggeredClick } from "../../utils/dom";
+import { isKeyboardTriggeredClick, isPrimaryPointerButton } from "../../utils/dom";
import type { Popover } from "./popover";
+const clickTolerance = 5;
+
+export function isDrag({
+ startX,
+ startY,
+ endX,
+ endY,
+}: {
+ startX: number;
+ startY: number;
+ endX: number;
+ endY: number;
+}): boolean {
+ const distance = Math.hypot(endX - startX, endY - startY);
+ return distance > clickTolerance;
+}
+
export default class PopoverManager {
// --------------------------------------------------------------------------
//
@@ -15,6 +32,8 @@ export default class PopoverManager {
private registeredElementCount = 0;
+ private pointerDownPosition?: { x: number; y: number };
+
// --------------------------------------------------------------------------
//
// Public Methods
@@ -86,20 +105,43 @@ export default class PopoverManager {
}
};
+ private pointerDownHandler = (event: PointerEvent): void => {
+ if (event.defaultPrevented || !isPrimaryPointerButton(event)) {
+ return;
+ }
+
+ const { clientX, clientY } = event;
+ this.pointerDownPosition = { x: clientX, y: clientY };
+ };
+
private clickHandler = (event: PointerEvent): void => {
- if (isKeyboardTriggeredClick(event) || event.defaultPrevented || window.getSelection()?.type === "Range") {
+ if (
+ isKeyboardTriggeredClick(event) ||
+ event.defaultPrevented ||
+ (this.pointerDownPosition &&
+ isDrag({
+ endY: event.clientY,
+ endX: event.clientX,
+ startY: this.pointerDownPosition.y,
+ startX: this.pointerDownPosition.x,
+ }))
+ ) {
return;
}
+ this.pointerDownPosition = undefined;
+
this.togglePopovers(event);
};
private addListeners(): void {
+ window.addEventListener("pointerdown", this.pointerDownHandler);
window.addEventListener("click", this.clickHandler);
window.addEventListener("keydown", this.keyDownHandler);
}
private removeListeners(): void {
+ window.removeEventListener("pointerdown", this.pointerDownHandler);
window.removeEventListener("click", this.clickHandler);
window.removeEventListener("keydown", this.keyDownHandler);
}
diff --git a/packages/calcite-components/src/components/popover/popover.e2e.ts b/packages/calcite-components/src/components/popover/popover.e2e.ts
index 88ea382d5d5..4de83a79798 100644
--- a/packages/calcite-components/src/components/popover/popover.e2e.ts
+++ b/packages/calcite-components/src/components/popover/popover.e2e.ts
@@ -400,49 +400,24 @@ describe("calcite-popover", () => {
expect(await popover.getProperty("open")).toBe(false);
});
- it("should not toggle popovers if selection range is present", async () => {
- const page = await newE2EPage();
-
- await page.setContent(html`
- Content
-
- `);
-
- const popover = await page.find("calcite-popover");
-
- expect(await popover.getProperty("open")).toBe(false);
-
- await page.$eval("button#ref", (el) => {
- const selection = window.getSelection();
- selection.removeAllRanges();
- const range = document.createRange();
- range.selectNode(el);
- selection.addRange(range);
- el.click();
- });
- await page.waitForChanges();
-
- expect(await popover.getProperty("open")).toBe(false);
- });
-
- it("should not close active popover if selection range occurs within the popover", async () => {
+ it("should not close active popover if click starts within the popover but ends outside", async () => {
const page = await newE2EPage();
await page.setContent(html`
Content
+
Outside node
`);
const popover = await page.find("calcite-popover");
expect(await popover.getProperty("open")).toBe(true);
- await page.$eval("div#content", (el) => {
- const selection = window.getSelection();
- selection.removeAllRanges();
- const range = document.createRange();
- range.selectNode(el);
- selection.addRange(range);
+ await page.evaluate(() => {
+ const content = document.getElementById("content");
+ content.dispatchEvent(new MouseEvent("pointerdown", { bubbles: true }));
+ const outsideNode = document.getElementById("outsideNode");
+ outsideNode.dispatchEvent(new MouseEvent("pointerup", { bubbles: true }));
});
await page.waitForChanges();
@@ -453,16 +428,6 @@ describe("calcite-popover", () => {
await ref.click();
await page.waitForChanges();
- expect(await popover.getProperty("open")).toBe(true);
-
- await page.evaluate(() => {
- const selection = window.getSelection();
- selection.removeAllRanges();
- });
-
- await ref.click();
- await page.waitForChanges();
-
expect(await popover.getProperty("open")).toBe(false);
});
diff --git a/packages/calcite-components/src/components/tooltip/TooltipManager.ts b/packages/calcite-components/src/components/tooltip/TooltipManager.ts
index 551f09fda7a..8610d06bcdb 100644
--- a/packages/calcite-components/src/components/tooltip/TooltipManager.ts
+++ b/packages/calcite-components/src/components/tooltip/TooltipManager.ts
@@ -98,22 +98,12 @@ export default class TooltipManager {
}
};
- private activeTooltipHasSelection(): boolean {
- const selection = window.getSelection();
- return selection?.type === "Range" && this.activeTooltip?.contains(selection?.anchorNode);
- }
-
private pointerLeaveHandler = (event: PointerEvent): void => {
if (event.defaultPrevented) {
return;
}
this.clearHoverTimeout();
-
- if (this.activeTooltipHasSelection()) {
- return;
- }
-
this.closeHoveredTooltip();
};
@@ -127,7 +117,7 @@ export default class TooltipManager {
const tooltip = this.queryTooltip(composedPath);
- if (this.activeTooltipHasSelection() || this.pathHasOpenTooltip(tooltip, composedPath)) {
+ if (this.pathHasOpenTooltip(tooltip, composedPath)) {
this.clearHoverTimeout();
return;
}
@@ -159,8 +149,8 @@ export default class TooltipManager {
);
}
- private clickHandler = (event: Event): void => {
- if (event.defaultPrevented || window.getSelection()?.type === "Range") {
+ private clickHandler = (event: PointerEvent): void => {
+ if (event.defaultPrevented) {
return;
}
diff --git a/packages/calcite-components/src/components/tooltip/tooltip.e2e.ts b/packages/calcite-components/src/components/tooltip/tooltip.e2e.ts
index 3df5b1ce3ac..e0a778c596b 100644
--- a/packages/calcite-components/src/components/tooltip/tooltip.e2e.ts
+++ b/packages/calcite-components/src/components/tooltip/tooltip.e2e.ts
@@ -706,84 +706,6 @@ describe("calcite-tooltip", () => {
expect(await hoverTip.getProperty("open")).toBe(false);
});
- it("should not open on click if selection range is present", async () => {
- const page = await newE2EPage();
-
- await page.setContent(html`
- Content
-
- Selection
- `);
-
- const hoverTip = await page.find("#hoverTip");
-
- expect(await hoverTip.getProperty("open")).toBe(false);
-
- await page.$eval("div#selection", (el) => {
- const selection = window.getSelection();
- selection.removeAllRanges();
- const range = document.createRange();
- range.selectNode(el);
- selection.addRange(range);
- });
-
- await dispatchClickEvent(page, "#hoverRef");
- await page.waitForTimeout(TOOLTIP_OPEN_DELAY_MS);
-
- expect(await hoverTip.getProperty("open")).toBe(false);
-
- await page.evaluate(() => {
- const selection = window.getSelection();
- selection.removeAllRanges();
- });
- await page.waitForChanges();
-
- await dispatchClickEvent(page, "#hoverRef");
- await page.waitForTimeout(TOOLTIP_OPEN_DELAY_MS);
-
- expect(await hoverTip.getProperty("open")).toBe(true);
- });
-
- it("should not close if selection range occurs within the tooltip", async () => {
- const page = await newE2EPage();
-
- await page.setContent(html`
-
- Content
-
- `);
-
- const hoverTip = await page.find("#hoverTip");
- await dispatchPointerEvent(page, "#hoverRef");
- await page.waitForTimeout(TOOLTIP_OPEN_DELAY_MS);
- expect(await hoverTip.getProperty("open")).toBe(true);
-
- await page.$eval("div#content", (el) => {
- const selection = window.getSelection();
- selection.removeAllRanges();
- const range = document.createRange();
- range.selectNode(el);
- selection.addRange(range);
- });
- await page.waitForChanges();
-
- await dispatchPointerEvent(page, "#otherRef");
- await page.waitForTimeout(TOOLTIP_CLOSE_DELAY_MS);
-
- expect(await hoverTip.getProperty("open")).toBe(true);
-
- await page.evaluate(() => {
- const selection = window.getSelection();
- selection.removeAllRanges();
- });
- await page.waitForChanges();
-
- await dispatchPointerEvent(page, "#otherRef");
- await page.waitForTimeout(TOOLTIP_CLOSE_DELAY_MS);
-
- expect(await hoverTip.getProperty("open")).toBe(false);
- });
-
describe("owns a floating-ui", () => {
floatingUIOwner(
`contentreferenceElement
`,