Skip to content

Commit

Permalink
fix: tooltips remain visible when hovered (microsoft#5701)
Browse files Browse the repository at this point in the history
* tooltip hover

* Change files

* feedback tweak
  • Loading branch information
Stephane Comeau authored Mar 4, 2022
1 parent ef742a5 commit b9eb24e
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 30 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "tooltip hover",
"packageName": "@microsoft/fast-components",
"email": "scomea@microsoft.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "tooltip hover",
"packageName": "@microsoft/fast-foundation",
"email": "scomea@microsoft.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,35 +106,51 @@ <h2>Show/Hide with auto updating and lock to viewport for Corner Positions</h2>

<h2>Fixed positions</h2>
<div style="height: 400px; width: 400px; background: lightgray; overflow: scroll;">
<fast-tooltip position="top" anchor="anchor-positions">
<fast-tooltip anchor="anchor-positions" position="top" style="position: absolute;">
Top
</fast-tooltip>

<fast-tooltip anchor="anchor-positions" position="right">
<fast-tooltip anchor="anchor-positions" position="right" style="position: absolute;">
Right
</fast-tooltip>

<fast-tooltip anchor="anchor-positions" position="bottom">
<fast-tooltip anchor="anchor-positions" position="bottom" style="position: absolute;">
Bottom
</fast-tooltip>

<fast-tooltip anchor="anchor-positions" position="left">
<fast-tooltip anchor="anchor-positions" position="left" style="position: absolute;">
Left
</fast-tooltip>

<fast-tooltip anchor="anchor-positions" position="top-left">
<fast-tooltip
anchor="anchor-positions"
position="top-left"
style="position: absolute;"
>
Top Left
</fast-tooltip>

<fast-tooltip anchor="anchor-positions" position="top-right">
<fast-tooltip
anchor="anchor-positions"
position="top-right"
style="position: absolute;"
>
Top Right
</fast-tooltip>

<fast-tooltip anchor="anchor-positions" position="bottom-left">
<fast-tooltip
anchor="anchor-positions"
position="bottom-left"
style="position: absolute;"
>
Bottom Left
</fast-tooltip>

<fast-tooltip anchor="anchor-positions" position="bottom-right">
<fast-tooltip
anchor="anchor-positions"
position="bottom-right"
style="position: absolute;"
>
Bottom Right
</fast-tooltip>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ export const tooltipStyles: (
align-items: center;
overflow: visible;
flex-direction: row;
pointer-events: none;
}
${anchoredRegionTag}.right,
Expand Down
117 changes: 96 additions & 21 deletions packages/web-components/fast-foundation/src/tooltip/tooltip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ export class Tooltip extends FoundationElement {
.querySelectorAll(":hover")
.forEach(element => {
if (element.id === anchorId) {
this.startHoverTimer();
this.startShowDelayTimer();
}
});
}
Expand Down Expand Up @@ -256,13 +256,23 @@ export class Tooltip extends FoundationElement {
/**
* The timer that tracks delay time before the tooltip is shown on hover
*/
private delayTimer: number | null = null;
private showDelayTimer: number | null = null;

/**
* Indicates whether the anchor is currently being hovered
* The timer that tracks delay time before the tooltip is hidden
*/
private hideDelayTimer: number | null = null;

/**
* Indicates whether the anchor is currently being hovered or has focus
*/
private isAnchorHoveredFocused: boolean = false;

/**
* Indicates whether the region is currently being hovered
*/
private isRegionHovered: boolean = false;

public connectedCallback(): void {
super.connectedCallback();
this.anchorElement = this.getAnchor();
Expand All @@ -271,7 +281,8 @@ export class Tooltip extends FoundationElement {

public disconnectedCallback(): void {
this.hideTooltip();
this.clearDelayTimer();
this.clearShowDelayTimer();
this.clearHideDelayTimer();
super.disconnectedCallback();
}

Expand Down Expand Up @@ -309,43 +320,96 @@ export class Tooltip extends FoundationElement {
);
};

/**
* mouse enters region
*/
private handleRegionMouseOver = (ev: Event): void => {
this.isRegionHovered = true;
};

/**
* mouse leaves region
*/
private handleRegionMouseOut = (ev: Event): void => {
this.isRegionHovered = false;
this.startHideDelayTimer();
};

/**
* mouse enters anchor
*/
private handleAnchorMouseOver = (ev: Event): void => {
this.startHoverTimer();
if (this.tooltipVisible) {
// tooltip is already visible, just set the anchor hover flag
this.isAnchorHoveredFocused = true;
return;
}
this.startShowDelayTimer();
};

/**
* mouse leaves anchor
*/
private handleAnchorMouseOut = (ev: Event): void => {
this.isAnchorHoveredFocused = false;
this.updateTooltipVisibility();
this.clearDelayTimer();
this.clearShowDelayTimer();
this.startHideDelayTimer();
};

/**
* anchor gets focus
*/
private handleAnchorFocusIn = (ev: Event): void => {
this.startHoverTimer();
this.startShowDelayTimer();
};

/**
* anchor loses focus
*/
private handleAnchorFocusOut = (ev: Event): void => {
this.isAnchorHoveredFocused = false;
this.updateTooltipVisibility();
this.clearDelayTimer();
this.clearShowDelayTimer();
this.startHideDelayTimer();
};

/**
* starts the hide timer
*/
private startHideDelayTimer = (): void => {
this.clearHideDelayTimer();

if (!this.tooltipVisible) {
return;
}

// allow 60 ms for account for pointer to move between anchor/tooltip
// without hiding tooltip
this.hideDelayTimer = window.setTimeout((): void => {
this.updateTooltipVisibility();
}, 60);
};

/**
* clears the hide delay
*/
private clearHideDelayTimer = (): void => {
if (this.hideDelayTimer !== null) {
clearTimeout(this.hideDelayTimer);
this.hideDelayTimer = null;
}
};

/**
* starts the hover timer if not currently running
* starts the show timer if not currently running
*/
private startHoverTimer = (): void => {
private startShowDelayTimer = (): void => {
if (this.isAnchorHoveredFocused) {
return;
}

if (this.delay > 1) {
if (this.delayTimer === null)
this.delayTimer = window.setTimeout((): void => {
if (this.showDelayTimer === null)
this.showDelayTimer = window.setTimeout((): void => {
this.startHover();
}, this.delay);
return;
Expand All @@ -355,20 +419,20 @@ export class Tooltip extends FoundationElement {
};

/**
* starts the hover delay timer
* start hover
*/
private startHover = (): void => {
this.isAnchorHoveredFocused = true;
this.updateTooltipVisibility();
};

/**
* clears the hover delay
* clears the show delay
*/
private clearDelayTimer = (): void => {
if (this.delayTimer !== null) {
clearTimeout(this.delayTimer);
this.delayTimer = null;
private clearShowDelayTimer = (): void => {
if (this.showDelayTimer !== null) {
clearTimeout(this.showDelayTimer);
this.showDelayTimer = null;
}
};

Expand Down Expand Up @@ -481,7 +545,7 @@ export class Tooltip extends FoundationElement {
this.showTooltip();
return;
} else {
if (this.isAnchorHoveredFocused) {
if (this.isAnchorHoveredFocused || this.isRegionHovered) {
this.showTooltip();
return;
}
Expand Down Expand Up @@ -509,13 +573,17 @@ export class Tooltip extends FoundationElement {
if (!this.tooltipVisible) {
return;
}
this.clearHideDelayTimer();
if (this.region !== null && this.region !== undefined) {
(this.region as any).removeEventListener(
"positionchange",
this.handlePositionChange
);
this.region.viewportElement = null;
this.region.anchorElement = null;

this.region.removeEventListener("mouseover", this.handleRegionMouseOver);
this.region.removeEventListener("mouseout", this.handleRegionMouseOut);
}
document.removeEventListener("keydown", this.handleDocumentKeydown);
this.tooltipVisible = false;
Expand All @@ -535,5 +603,12 @@ export class Tooltip extends FoundationElement {
"positionchange",
this.handlePositionChange
);

this.region.addEventListener("mouseover", this.handleRegionMouseOver, {
passive: true,
});
this.region.addEventListener("mouseout", this.handleRegionMouseOut, {
passive: true,
});
};
}

0 comments on commit b9eb24e

Please sign in to comment.