merge: Fix unwanted hover effects on touch devices (!1251)

View MR for information: https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/1251

Approved-by: dakkar <dakkar@thenautilus.net>
Approved-by: Marie <github@yuugi.dev>
This commit is contained in:
dakkar 2025-12-24 13:12:01 +00:00
commit 78e725bd05
3 changed files with 12 additions and 16 deletions

View file

@ -11,7 +11,7 @@ SPDX-License-Identifier: AGPL-3.0-only
:leaveToClass="prefer.s.animation ? $style.transition_popup_leaveTo : ''"
appear @afterLeave="emit('closed')"
>
<div v-if="showing" :class="$style.root" class="_popup _shadow" :style="{ zIndex, top: top + 'px', left: left + 'px' }" @mouseover="() => { emit('mouseover'); }" @mouseleave="() => { emit('mouseleave'); }">
<div v-if="showing" :class="$style.root" class="_popup _shadow" :style="{ zIndex, top: top + 'px', left: left + 'px' }" @pointerover="(event) => { emit('pointerover', event); }" @mouseleave="() => { emit('mouseleave'); }">
<MkError v-if="error" @retry="fetchUser()"/>
<div v-else-if="user != null">
<div :class="$style.banner" :style="user.bannerUrl ? { backgroundImage: `url(${prefer.s.disableShowingAnimatedImages ? getStaticImageUrl(user.bannerUrl) : user.bannerUrl})` } : ''">
@ -92,7 +92,7 @@ const props = defineProps<{
const emit = defineEmits<{
(ev: 'closed'): void;
(ev: 'mouseover'): void;
(ev: 'pointerover', event: PointerEvent): void;
(ev: 'mouseleave'): void;
}>();

View file

@ -21,7 +21,7 @@ export class UserPreview {
this.show = this.show.bind(this);
this.close = this.close.bind(this);
this.onMouseover = this.onMouseover.bind(this);
this.onPointerover = this.onPointerover.bind(this);
this.onMouseleave = this.onMouseleave.bind(this);
this.onClick = this.onClick.bind(this);
this.attach = this.attach.bind(this);
@ -41,7 +41,8 @@ export class UserPreview {
q: this.user,
source: this.el,
}, {
mouseover: () => {
pointerover: (event: PointerEvent) => {
if (event.pointerType === 'touch') return;
window.clearTimeout(this.hideTimer);
},
mouseleave: () => {
@ -74,7 +75,8 @@ export class UserPreview {
}
}
private onMouseover() {
private onPointerover(event: PointerEvent) {
if (event.pointerType === 'touch') return;
window.clearTimeout(this.showTimer);
window.clearTimeout(this.hideTimer);
this.showTimer = window.setTimeout(this.show, 500);
@ -92,13 +94,13 @@ export class UserPreview {
}
public attach() {
this.el.addEventListener('mouseover', this.onMouseover);
this.el.addEventListener('pointerover', this.onPointerover);
this.el.addEventListener('mouseleave', this.onMouseleave);
this.el.addEventListener('click', this.onClick);
}
public detach() {
this.el.removeEventListener('mouseover', this.onMouseover);
this.el.removeEventListener('pointerover', this.onPointerover);
this.el.removeEventListener('mouseleave', this.onMouseleave);
this.el.removeEventListener('click', this.onClick);
}

View file

@ -13,11 +13,6 @@ export function useTooltip(
): void {
let isHovering = false;
// iOS(Androidも)では、要素をタップした直後に(おせっかいで)mouseoverイベントを発火させたりするため、それを無視するためのフラグ
// 無視しないと、画面に触れてないのにツールチップが出たりし、ユーザビリティが損なわれる
// TODO: 一度でもタップすると二度とマウスでツールチップ出せなくなるのをどうにかする 定期的にfalseに戻すとか...
let shouldIgnoreMouseover = false;
let timeoutId: number;
let changeShowingState: (() => void) | null;
@ -55,9 +50,9 @@ export function useTooltip(
}
};
const onMouseover = () => {
const onPointerover = (event: PointerEvent) => {
if (event.pointerType === 'touch') return;
if (isHovering) return;
if (shouldIgnoreMouseover) return;
isHovering = true;
timeoutId = window.setTimeout(open, delay);
};
@ -71,7 +66,6 @@ export function useTooltip(
};
const onTouchstart = () => {
shouldIgnoreMouseover = true;
if (isHovering) return;
isHovering = true;
timeoutId = window.setTimeout(open, delay);
@ -89,7 +83,7 @@ export function useTooltip(
if (elRef.value) {
stop();
const el = elRef.value instanceof Element ? elRef.value : elRef.value.$el;
el.addEventListener('mouseover', onMouseover, { passive: true });
el.addEventListener('pointerover', onPointerover, { passive: true });
el.addEventListener('mouseleave', onMouseleave, { passive: true });
el.addEventListener('touchstart', onTouchstart, { passive: true });
el.addEventListener('touchend', onTouchend, { passive: true });