From c79dee964b3ef0f8fe7f633b1462757977615fe9 Mon Sep 17 00:00:00 2001 From: Matt Driscoll Date: Mon, 28 Jul 2025 11:10:59 -0700 Subject: [PATCH 1/5] fix(popover, tooltip): selection range within an open component should open or close the component #12589 --- .../src/components/popover/PopoverManager.ts | 9 ++- .../src/components/popover/popover.e2e.ts | 25 -------- .../src/components/tooltip/TooltipManager.ts | 13 ++-- .../src/components/tooltip/tooltip.e2e.ts | 38 ----------- .../calcite-components/src/utils/dom.e2e.ts | 63 ++++++++++++++++++- packages/calcite-components/src/utils/dom.ts | 11 ++++ 6 files changed, 84 insertions(+), 75 deletions(-) diff --git a/packages/calcite-components/src/components/popover/PopoverManager.ts b/packages/calcite-components/src/components/popover/PopoverManager.ts index 74cc669c574..0fab1b5f04a 100644 --- a/packages/calcite-components/src/components/popover/PopoverManager.ts +++ b/packages/calcite-components/src/components/popover/PopoverManager.ts @@ -1,7 +1,7 @@ // @ts-strict-ignore import { ReferenceElement } from "../../utils/floating-ui"; import { isActivationKey } from "../../utils/key"; -import { isKeyboardTriggeredClick } from "../../utils/dom"; +import { elementHasSelectionRange, isKeyboardTriggeredClick } from "../../utils/dom"; import type { Popover } from "./popover"; export default class PopoverManager { @@ -86,8 +86,13 @@ export default class PopoverManager { } }; + private openPopoverHasSelection(): boolean { + const { registeredElements } = this; + return Array.from(registeredElements.values()).some((popover) => popover.open && elementHasSelectionRange(popover)); + } + private clickHandler = (event: PointerEvent): void => { - if (isKeyboardTriggeredClick(event) || event.defaultPrevented || window.getSelection()?.type === "Range") { + if (isKeyboardTriggeredClick(event) || event.defaultPrevented || this.openPopoverHasSelection()) { return; } diff --git a/packages/calcite-components/src/components/popover/popover.e2e.ts b/packages/calcite-components/src/components/popover/popover.e2e.ts index 88ea382d5d5..00e25678ea1 100644 --- a/packages/calcite-components/src/components/popover/popover.e2e.ts +++ b/packages/calcite-components/src/components/popover/popover.e2e.ts @@ -400,31 +400,6 @@ 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 () => { const page = await newE2EPage(); diff --git a/packages/calcite-components/src/components/tooltip/TooltipManager.ts b/packages/calcite-components/src/components/tooltip/TooltipManager.ts index 551f09fda7a..fe3d485055b 100644 --- a/packages/calcite-components/src/components/tooltip/TooltipManager.ts +++ b/packages/calcite-components/src/components/tooltip/TooltipManager.ts @@ -1,5 +1,5 @@ // @ts-strict-ignore -import { getShadowRootNode } from "../../utils/dom"; +import { elementHasSelectionRange, getShadowRootNode } from "../../utils/dom"; import { ReferenceElement } from "../../utils/floating-ui"; import { TOOLTIP_OPEN_DELAY_MS, TOOLTIP_QUICK_OPEN_DELAY_MS, TOOLTIP_CLOSE_DELAY_MS } from "./resources"; import { getEffectiveReferenceElement } from "./utils"; @@ -98,11 +98,6 @@ 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; @@ -110,7 +105,7 @@ export default class TooltipManager { this.clearHoverTimeout(); - if (this.activeTooltipHasSelection()) { + if (elementHasSelectionRange(this.activeTooltip)) { return; } @@ -127,7 +122,7 @@ export default class TooltipManager { const tooltip = this.queryTooltip(composedPath); - if (this.activeTooltipHasSelection() || this.pathHasOpenTooltip(tooltip, composedPath)) { + if (elementHasSelectionRange(this.activeTooltip) || this.pathHasOpenTooltip(tooltip, composedPath)) { this.clearHoverTimeout(); return; } @@ -160,7 +155,7 @@ export default class TooltipManager { } private clickHandler = (event: Event): void => { - if (event.defaultPrevented || window.getSelection()?.type === "Range") { + 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..e21f759d04d 100644 --- a/packages/calcite-components/src/components/tooltip/tooltip.e2e.ts +++ b/packages/calcite-components/src/components/tooltip/tooltip.e2e.ts @@ -706,44 +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(); diff --git a/packages/calcite-components/src/utils/dom.e2e.ts b/packages/calcite-components/src/utils/dom.e2e.ts index 98fec5d23d2..9b6f9705f47 100644 --- a/packages/calcite-components/src/utils/dom.e2e.ts +++ b/packages/calcite-components/src/utils/dom.e2e.ts @@ -1,7 +1,7 @@ // @ts-strict-ignore import { newE2EPage, E2EPage } from "@arcgis/lumina-compiler/puppeteerTesting"; import { describe, expect, it, beforeEach } from "vitest"; -import { getHost, getRootNode, queryElementRoots } from "./dom"; +import { elementHasSelectionRange, getHost, getRootNode, queryElementRoots } from "./dom"; interface SetUpTestComponentOptions { insideHostHTML: string; @@ -188,3 +188,64 @@ describe("queries", () => { expect(text).toBe(outsideHost); }); }); + +describe("elementHasSelection", () => { + let el: HTMLElement; + let child: HTMLElement; + + beforeEach(() => { + el = document.createElement("div"); + child = document.createElement("span"); + child.textContent = "Hello world"; + el.appendChild(child); + document.body.appendChild(el); + }); + + afterEach(() => { + document.body.removeChild(el); + window.getSelection().removeAllRanges(); + }); + + it("returns false when there is no selection", () => { + expect(elementHasSelectionRange(el)).toBe(false); + }); + + it("returns true when selection is inside the element (anchorNode)", () => { + const range = document.createRange(); + range.selectNodeContents(child); + const selection = window.getSelection(); + selection.removeAllRanges(); + selection.addRange(range); + expect(elementHasSelectionRange(el)).toBe(true); + }); + + it("returns true when selection focusNode is inside the element (reverse selection)", () => { + const range = document.createRange(); + range.setStart(child.firstChild, 5); + range.setEnd(child.firstChild, 0); + const selection = window.getSelection(); + selection.removeAllRanges(); + selection.addRange(range); + // focusNode should be child, anchorNode should be child + expect(elementHasSelectionRange(el)).toBe(true); + }); + + it("returns false when selection is outside the element", () => { + const outside = document.createElement("div"); + outside.textContent = "Outside"; + document.body.appendChild(outside); + const range = document.createRange(); + range.selectNodeContents(outside); + const selection = window.getSelection(); + selection.removeAllRanges(); + selection.addRange(range); + expect(elementHasSelectionRange(el)).toBe(false); + document.body.removeChild(outside); + }); + + it("returns false when selection is empty", () => { + const selection = window.getSelection(); + selection.removeAllRanges(); + expect(elementHasSelectionRange(el)).toBe(false); + }); +}); diff --git a/packages/calcite-components/src/utils/dom.ts b/packages/calcite-components/src/utils/dom.ts index 006809c5e17..c261ac19b33 100644 --- a/packages/calcite-components/src/utils/dom.ts +++ b/packages/calcite-components/src/utils/dom.ts @@ -730,3 +730,14 @@ export function viewportUnitToPixel(value: number, viewportSize: number): number // intentionally dividing last to avoid rounding errors return (value * viewportSize) / 100; } + +/** + * Checks if the given element contains the current text selection. + * + * @param {HTMLElement} el - The element to check for selection containment. + * @returns {boolean} True if the element contains a non-empty selection, otherwise false. + */ +export function elementHasSelectionRange(el: HTMLElement): boolean { + const selection = window.getSelection(); + return selection.type === "Range" && el && (el.contains(selection.anchorNode) || el.contains(selection.focusNode)); +} From f93412512005e0f3ce440b0d5490fd783b8d79aa Mon Sep 17 00:00:00 2001 From: Matt Driscoll Date: Mon, 28 Jul 2025 11:39:22 -0700 Subject: [PATCH 2/5] fix test --- packages/calcite-components/src/utils/dom.e2e.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/calcite-components/src/utils/dom.e2e.ts b/packages/calcite-components/src/utils/dom.e2e.ts index 9b6f9705f47..b3f70febf6a 100644 --- a/packages/calcite-components/src/utils/dom.e2e.ts +++ b/packages/calcite-components/src/utils/dom.e2e.ts @@ -1,6 +1,6 @@ // @ts-strict-ignore import { newE2EPage, E2EPage } from "@arcgis/lumina-compiler/puppeteerTesting"; -import { describe, expect, it, beforeEach } from "vitest"; +import { describe, expect, it, beforeEach, afterEach } from "vitest"; import { elementHasSelectionRange, getHost, getRootNode, queryElementRoots } from "./dom"; interface SetUpTestComponentOptions { From 9d8514fc191b484716541e293df4eeb52be76df3 Mon Sep 17 00:00:00 2001 From: Matt Driscoll Date: Mon, 28 Jul 2025 11:52:26 -0700 Subject: [PATCH 3/5] fix test --- packages/calcite-components/src/utils/dom.e2e.ts | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/packages/calcite-components/src/utils/dom.e2e.ts b/packages/calcite-components/src/utils/dom.e2e.ts index b3f70febf6a..9dcdff4588b 100644 --- a/packages/calcite-components/src/utils/dom.e2e.ts +++ b/packages/calcite-components/src/utils/dom.e2e.ts @@ -210,7 +210,7 @@ describe("elementHasSelection", () => { expect(elementHasSelectionRange(el)).toBe(false); }); - it("returns true when selection is inside the element (anchorNode)", () => { + it("returns true when selection is inside the element", () => { const range = document.createRange(); range.selectNodeContents(child); const selection = window.getSelection(); @@ -219,17 +219,6 @@ describe("elementHasSelection", () => { expect(elementHasSelectionRange(el)).toBe(true); }); - it("returns true when selection focusNode is inside the element (reverse selection)", () => { - const range = document.createRange(); - range.setStart(child.firstChild, 5); - range.setEnd(child.firstChild, 0); - const selection = window.getSelection(); - selection.removeAllRanges(); - selection.addRange(range); - // focusNode should be child, anchorNode should be child - expect(elementHasSelectionRange(el)).toBe(true); - }); - it("returns false when selection is outside the element", () => { const outside = document.createElement("div"); outside.textContent = "Outside"; From ddd86838eb3f9043afd979513a2193da443ab8c9 Mon Sep 17 00:00:00 2001 From: Matt Driscoll Date: Mon, 28 Jul 2025 15:51:38 -0700 Subject: [PATCH 4/5] refactor --- .../src/components/popover/PopoverManager.ts | 48 ++++++++++++++--- .../src/components/popover/popover.e2e.ts | 24 +++------ .../src/components/tooltip/TooltipManager.ts | 11 ++-- .../src/components/tooltip/tooltip.e2e.ts | 40 -------------- .../calcite-components/src/utils/dom.e2e.ts | 54 +------------------ packages/calcite-components/src/utils/dom.ts | 11 ---- 6 files changed, 54 insertions(+), 134 deletions(-) diff --git a/packages/calcite-components/src/components/popover/PopoverManager.ts b/packages/calcite-components/src/components/popover/PopoverManager.ts index 0fab1b5f04a..a9775fd4a0f 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 { elementHasSelectionRange, isKeyboardTriggeredClick } from "../../utils/dom"; +import { isKeyboardTriggeredClick, isPrimaryPointerButton } from "../../utils/dom"; import type { Popover } from "./popover"; +const clickTolerance = 5; + +export function isDragEvent({ + startX, + startY, + endX, + endY, +}: { + startX: number; + startY: number; + endX: number; + endY: number; +}): boolean { + const distance = Math.sqrt(Math.pow(endX - startX, 2) + Math.pow(endY - startY, 2)); + return distance > clickTolerance; +} + export default class PopoverManager { // -------------------------------------------------------------------------- // @@ -15,6 +32,8 @@ export default class PopoverManager { private registeredElementCount = 0; + private pointerDownPosition?: { startX: number; startY: number }; + // -------------------------------------------------------------------------- // // Public Methods @@ -86,25 +105,42 @@ export default class PopoverManager { } }; - private openPopoverHasSelection(): boolean { - const { registeredElements } = this; - return Array.from(registeredElements.values()).some((popover) => popover.open && elementHasSelectionRange(popover)); - } + private pointerDownHandler = (event: PointerEvent): void => { + if (event.defaultPrevented || !isPrimaryPointerButton(event)) { + return; + } + + const { clientX, clientY } = event; + this.pointerDownPosition = { startX: clientX, startY: clientY }; + }; private clickHandler = (event: PointerEvent): void => { - if (isKeyboardTriggeredClick(event) || event.defaultPrevented || this.openPopoverHasSelection()) { + if ( + isKeyboardTriggeredClick(event) || + event.defaultPrevented || + (this.pointerDownPosition && + isDragEvent({ + endY: event.clientY, + endX: event.clientX, + ...this.pointerDownPosition, + })) + ) { 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 00e25678ea1..4de83a79798 100644 --- a/packages/calcite-components/src/components/popover/popover.e2e.ts +++ b/packages/calcite-components/src/components/popover/popover.e2e.ts @@ -400,24 +400,24 @@ describe("calcite-popover", () => { 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(); @@ -428,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 fe3d485055b..8610d06bcdb 100644 --- a/packages/calcite-components/src/components/tooltip/TooltipManager.ts +++ b/packages/calcite-components/src/components/tooltip/TooltipManager.ts @@ -1,5 +1,5 @@ // @ts-strict-ignore -import { elementHasSelectionRange, getShadowRootNode } from "../../utils/dom"; +import { getShadowRootNode } from "../../utils/dom"; import { ReferenceElement } from "../../utils/floating-ui"; import { TOOLTIP_OPEN_DELAY_MS, TOOLTIP_QUICK_OPEN_DELAY_MS, TOOLTIP_CLOSE_DELAY_MS } from "./resources"; import { getEffectiveReferenceElement } from "./utils"; @@ -104,11 +104,6 @@ export default class TooltipManager { } this.clearHoverTimeout(); - - if (elementHasSelectionRange(this.activeTooltip)) { - return; - } - this.closeHoveredTooltip(); }; @@ -122,7 +117,7 @@ export default class TooltipManager { const tooltip = this.queryTooltip(composedPath); - if (elementHasSelectionRange(this.activeTooltip) || this.pathHasOpenTooltip(tooltip, composedPath)) { + if (this.pathHasOpenTooltip(tooltip, composedPath)) { this.clearHoverTimeout(); return; } @@ -154,7 +149,7 @@ export default class TooltipManager { ); } - private clickHandler = (event: Event): void => { + 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 e21f759d04d..e0a778c596b 100644 --- a/packages/calcite-components/src/components/tooltip/tooltip.e2e.ts +++ b/packages/calcite-components/src/components/tooltip/tooltip.e2e.ts @@ -706,46 +706,6 @@ describe("calcite-tooltip", () => { expect(await hoverTip.getProperty("open")).toBe(false); }); - 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( `content
referenceElement
`, diff --git a/packages/calcite-components/src/utils/dom.e2e.ts b/packages/calcite-components/src/utils/dom.e2e.ts index 9dcdff4588b..98fec5d23d2 100644 --- a/packages/calcite-components/src/utils/dom.e2e.ts +++ b/packages/calcite-components/src/utils/dom.e2e.ts @@ -1,7 +1,7 @@ // @ts-strict-ignore import { newE2EPage, E2EPage } from "@arcgis/lumina-compiler/puppeteerTesting"; -import { describe, expect, it, beforeEach, afterEach } from "vitest"; -import { elementHasSelectionRange, getHost, getRootNode, queryElementRoots } from "./dom"; +import { describe, expect, it, beforeEach } from "vitest"; +import { getHost, getRootNode, queryElementRoots } from "./dom"; interface SetUpTestComponentOptions { insideHostHTML: string; @@ -188,53 +188,3 @@ describe("queries", () => { expect(text).toBe(outsideHost); }); }); - -describe("elementHasSelection", () => { - let el: HTMLElement; - let child: HTMLElement; - - beforeEach(() => { - el = document.createElement("div"); - child = document.createElement("span"); - child.textContent = "Hello world"; - el.appendChild(child); - document.body.appendChild(el); - }); - - afterEach(() => { - document.body.removeChild(el); - window.getSelection().removeAllRanges(); - }); - - it("returns false when there is no selection", () => { - expect(elementHasSelectionRange(el)).toBe(false); - }); - - it("returns true when selection is inside the element", () => { - const range = document.createRange(); - range.selectNodeContents(child); - const selection = window.getSelection(); - selection.removeAllRanges(); - selection.addRange(range); - expect(elementHasSelectionRange(el)).toBe(true); - }); - - it("returns false when selection is outside the element", () => { - const outside = document.createElement("div"); - outside.textContent = "Outside"; - document.body.appendChild(outside); - const range = document.createRange(); - range.selectNodeContents(outside); - const selection = window.getSelection(); - selection.removeAllRanges(); - selection.addRange(range); - expect(elementHasSelectionRange(el)).toBe(false); - document.body.removeChild(outside); - }); - - it("returns false when selection is empty", () => { - const selection = window.getSelection(); - selection.removeAllRanges(); - expect(elementHasSelectionRange(el)).toBe(false); - }); -}); diff --git a/packages/calcite-components/src/utils/dom.ts b/packages/calcite-components/src/utils/dom.ts index c261ac19b33..006809c5e17 100644 --- a/packages/calcite-components/src/utils/dom.ts +++ b/packages/calcite-components/src/utils/dom.ts @@ -730,14 +730,3 @@ export function viewportUnitToPixel(value: number, viewportSize: number): number // intentionally dividing last to avoid rounding errors return (value * viewportSize) / 100; } - -/** - * Checks if the given element contains the current text selection. - * - * @param {HTMLElement} el - The element to check for selection containment. - * @returns {boolean} True if the element contains a non-empty selection, otherwise false. - */ -export function elementHasSelectionRange(el: HTMLElement): boolean { - const selection = window.getSelection(); - return selection.type === "Range" && el && (el.contains(selection.anchorNode) || el.contains(selection.focusNode)); -} From 3258d25f4638389e3df40d2822a7429e91e57010 Mon Sep 17 00:00:00 2001 From: Matt Driscoll Date: Wed, 6 Aug 2025 09:16:51 -0700 Subject: [PATCH 5/5] review fixes --- .../src/components/popover/PopoverManager.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/calcite-components/src/components/popover/PopoverManager.ts b/packages/calcite-components/src/components/popover/PopoverManager.ts index a9775fd4a0f..a295cf325e6 100644 --- a/packages/calcite-components/src/components/popover/PopoverManager.ts +++ b/packages/calcite-components/src/components/popover/PopoverManager.ts @@ -6,7 +6,7 @@ import type { Popover } from "./popover"; const clickTolerance = 5; -export function isDragEvent({ +export function isDrag({ startX, startY, endX, @@ -17,7 +17,7 @@ export function isDragEvent({ endX: number; endY: number; }): boolean { - const distance = Math.sqrt(Math.pow(endX - startX, 2) + Math.pow(endY - startY, 2)); + const distance = Math.hypot(endX - startX, endY - startY); return distance > clickTolerance; } @@ -32,7 +32,7 @@ export default class PopoverManager { private registeredElementCount = 0; - private pointerDownPosition?: { startX: number; startY: number }; + private pointerDownPosition?: { x: number; y: number }; // -------------------------------------------------------------------------- // @@ -111,7 +111,7 @@ export default class PopoverManager { } const { clientX, clientY } = event; - this.pointerDownPosition = { startX: clientX, startY: clientY }; + this.pointerDownPosition = { x: clientX, y: clientY }; }; private clickHandler = (event: PointerEvent): void => { @@ -119,10 +119,11 @@ export default class PopoverManager { isKeyboardTriggeredClick(event) || event.defaultPrevented || (this.pointerDownPosition && - isDragEvent({ + isDrag({ endY: event.clientY, endX: event.clientX, - ...this.pointerDownPosition, + startY: this.pointerDownPosition.y, + startX: this.pointerDownPosition.x, })) ) { return;