Do not show hovercards when the target pops up under the mouse

This is a random product excellence polish. It has personally annoyed
me for at least a year, and I have finally found the time to fix it.

Google-Bug-Id: b/158328061
Change-Id: I70842e26c7a46368c6f2ebcc3e1857b07d38d7a3
diff --git a/polygerrit-ui/app/mixins/hovercard-mixin/hovercard-mixin.ts b/polygerrit-ui/app/mixins/hovercard-mixin/hovercard-mixin.ts
index 793e5d6..fd4da4f 100644
--- a/polygerrit-ui/app/mixins/hovercard-mixin/hovercard-mixin.ts
+++ b/polygerrit-ui/app/mixins/hovercard-mixin/hovercard-mixin.ts
@@ -159,7 +159,12 @@
     }
 
     private addTargetEventListeners() {
-      this._target?.addEventListener('mouseenter', this.debounceShow);
+      // We intentionally listen on 'mousemove' instead of 'mouseenter', because
+      // otherwise the target appearing under the mouse cursor would also
+      // trigger the hovercard, which can annoying for the user, for example
+      // when added reviewer chips appear in the reply dialog via keyboard
+      // interaction.
+      this._target?.addEventListener('mousemove', this.debounceShow);
       this._target?.addEventListener('focus', this.debounceShow);
       this._target?.addEventListener('mouseleave', this.debounceHide);
       this._target?.addEventListener('blur', this.debounceHide);
@@ -167,7 +172,7 @@
     }
 
     private removeTargetEventListeners() {
-      this._target?.removeEventListener('mouseenter', this.debounceShow);
+      this._target?.removeEventListener('mousemove', this.debounceShow);
       this._target?.removeEventListener('focus', this.debounceShow);
       this._target?.removeEventListener('mouseleave', this.debounceHide);
       this._target?.removeEventListener('blur', this.debounceHide);
diff --git a/polygerrit-ui/app/mixins/hovercard-mixin/hovercard-mixin_test.ts b/polygerrit-ui/app/mixins/hovercard-mixin/hovercard-mixin_test.ts
index bd12789..dd86b38 100644
--- a/polygerrit-ui/app/mixins/hovercard-mixin/hovercard-mixin_test.ts
+++ b/polygerrit-ui/app/mixins/hovercard-mixin/hovercard-mixin_test.ts
@@ -130,12 +130,12 @@
   test('card is scheduled to show on enter and hides on leave', async () => {
     const button = document.querySelector('button');
     const enterPromise = mockPromise();
-    button!.addEventListener('mouseenter', () => enterPromise.resolve());
+    button!.addEventListener('mousemove', () => enterPromise.resolve());
     const leavePromise = mockPromise();
     button!.addEventListener('mouseleave', () => leavePromise.resolve());
 
     assert.isFalse(element._isShowing);
-    button!.dispatchEvent(new CustomEvent('mouseenter'));
+    button!.dispatchEvent(new CustomEvent('mousemove'));
 
     await enterPromise;
     await flush();
@@ -158,12 +158,12 @@
     const button = document.querySelector('button');
     const enterPromise = mockPromise();
     const clickPromise = mockPromise();
-    button!.addEventListener('mouseenter', () => enterPromise.resolve());
+    button!.addEventListener('mousemove', () => enterPromise.resolve());
     button!.addEventListener('click', () => clickPromise.resolve());
 
     assert.isFalse(element._isShowing);
 
-    button!.dispatchEvent(new CustomEvent('mouseenter'));
+    button!.dispatchEvent(new CustomEvent('mousemove'));
 
     await enterPromise;
     await flush();