Skip to content

Commit e2c9011

Browse files
authored
Cancel pending hover on mouse exit (#14533)
If the mouse exits before the HoverService has rendered its pop-up, cancel the pending presentation of that pop-up. Also fix the problem of it being difficult to mouse over to the pop-up itself after it is shown to interact with it (it being necessary to carefully track over the bottom triangle). This is accomplished by cancelling only after a short delay that allows the mouse to reach either the pop-up or the original hover target. Fixes #14532 Signed-off-by: Christian W. Damus <[email protected]>
1 parent 53c09a8 commit e2c9011

File tree

1 file changed

+12
-5
lines changed

1 file changed

+12
-5
lines changed

packages/core/src/browser/hover-service.ts

+12-5
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ import '../../src/browser/style/hover-service.css';
2525

2626
export type HoverPosition = 'left' | 'right' | 'top' | 'bottom';
2727

28+
// Threshold, in milliseconds, over which a mouse movement is not considered
29+
// quick enough as to be ignored
30+
const quickMouseThresholdMillis = 200;
31+
2832
export namespace HoverPosition {
2933
export function invertIfNecessary(position: HoverPosition, target: DOMRect, host: DOMRect, totalWidth: number, totalHeight: number): HoverPosition {
3034
if (position === 'left') {
@@ -100,11 +104,13 @@ export class HoverService {
100104
if (request.target !== this.hoverTarget) {
101105
this.cancelHover();
102106
this.pendingTimeout = disposableTimeout(() => this.renderHover(request), this.getHoverDelay());
107+
this.hoverTarget = request.target;
108+
this.listenForMouseOut();
103109
}
104110
}
105111

106112
protected getHoverDelay(): number {
107-
return Date.now() - this.lastHidHover < 200
113+
return Date.now() - this.lastHidHover < quickMouseThresholdMillis
108114
? 0
109115
: this.preferences.get('workbench.hover.delay', isOSX ? 1500 : 500);
110116
}
@@ -116,7 +122,6 @@ export class HoverService {
116122
if (cssClasses) {
117123
host.classList.add(...cssClasses);
118124
}
119-
this.hoverTarget = target;
120125
if (content instanceof HTMLElement) {
121126
host.appendChild(content);
122127
firstChild = content;
@@ -155,8 +160,6 @@ export class HoverService {
155160
}
156161
}
157162
});
158-
159-
this.listenForMouseOut();
160163
}
161164

162165
protected setHostPosition(target: HTMLElement, host: HTMLElement, position: HoverPosition): HoverPosition {
@@ -197,7 +200,11 @@ export class HoverService {
197200
protected listenForMouseOut(): void {
198201
const handleMouseMove = (e: MouseEvent) => {
199202
if (e.target instanceof Node && !this.hoverHost.contains(e.target) && !this.hoverTarget?.contains(e.target)) {
200-
this.cancelHover();
203+
this.disposeOnHide.push(disposableTimeout(() => {
204+
if (!this.hoverHost.matches(':hover') && !this.hoverTarget?.matches(':hover')) {
205+
this.cancelHover();
206+
}
207+
}, quickMouseThresholdMillis));
201208
}
202209
};
203210
document.addEventListener('mousemove', handleMouseMove);

0 commit comments

Comments
 (0)