Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export default class PopoverManager {
};

private clickHandler = (event: PointerEvent): void => {
if (isKeyboardTriggeredClick(event) || event.defaultPrevented) {
if (isKeyboardTriggeredClick(event) || event.defaultPrevented || window.getSelection()?.type === "Range") {
return;
}

Expand Down
66 changes: 66 additions & 0 deletions packages/calcite-components/src/components/popover/popover.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,72 @@ 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`
<calcite-popover reference-element="ref">Content</calcite-popover>
<button id="ref">Button</button>
`);

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();

await page.setContent(html`
<calcite-popover reference-element="ref" open><div id="content">Content</div></calcite-popover>
<button id="ref">Button</button>
`);

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.waitForChanges();

expect(await popover.getProperty("open")).toBe(true);

const ref = await page.find("#ref");

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);
});

it("should not be visible if reference is hidden", async () => {
const page = await newE2EPage();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,22 @@ export default class TooltipManager {
}
};

private pointerLeaveHandler = (): void => {
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();
};

Expand All @@ -110,11 +124,10 @@ export default class TooltipManager {
}

const composedPath = event.composedPath();
const { activeTooltip } = this;

const tooltip = this.queryTooltip(composedPath);

if (this.pathHasOpenTooltip(tooltip, composedPath)) {
if (this.activeTooltipHasSelection() || this.pathHasOpenTooltip(tooltip, composedPath)) {
this.clearHoverTimeout();
return;
}
Expand All @@ -131,7 +144,7 @@ export default class TooltipManager {

if (tooltip) {
this.openHoveredTooltip(tooltip);
} else if (activeTooltip?.open) {
} else if (this.activeTooltip?.open) {
this.closeHoveredTooltip();
}

Expand All @@ -147,7 +160,7 @@ export default class TooltipManager {
}

private clickHandler = (event: Event): void => {
if (event.defaultPrevented) {
if (event.defaultPrevented || window.getSelection()?.type === "Range") {
return;
}

Expand Down
78 changes: 78 additions & 0 deletions packages/calcite-components/src/components/tooltip/tooltip.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -706,6 +706,84 @@ 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`
<calcite-tooltip id="hoverTip" reference-element="hoverRef">Content</calcite-tooltip>
<button id="hoverRef">Button</button>
<div id="selection">Selection</div>
`);

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");
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to consolidate these new tests? It looks like they follow a similar structure and might even be generalized for reuse between popover & tooltip tests.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think they share enough to warrant that. Could be a refactor issue to investigate but I think they are mostly unique.

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`
<button id="otherRef">Other Button</button>
<calcite-tooltip id="hoverTip" reference-element="hoverRef"><div id="content">Content</div></calcite-tooltip>
<button id="hoverRef">Button</button>
`);

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(
`<calcite-tooltip reference-element="ref">content</calcite-tooltip><div id="ref">referenceElement</div>`,
Expand Down
Loading