diff options
Diffstat (limited to 'packages/client/src/scripts')
| -rw-r--r-- | packages/client/src/scripts/is-device-touch.ts | 1 | ||||
| -rw-r--r-- | packages/client/src/scripts/select-file.ts | 11 | ||||
| -rw-r--r-- | packages/client/src/scripts/touch.ts | 19 | ||||
| -rw-r--r-- | packages/client/src/scripts/use-tooltip.ts | 49 |
4 files changed, 67 insertions, 13 deletions
diff --git a/packages/client/src/scripts/is-device-touch.ts b/packages/client/src/scripts/is-device-touch.ts deleted file mode 100644 index 3f0bfefed2..0000000000 --- a/packages/client/src/scripts/is-device-touch.ts +++ /dev/null @@ -1 +0,0 @@ -export const isDeviceTouch = 'maxTouchPoints' in navigator && navigator.maxTouchPoints > 0; diff --git a/packages/client/src/scripts/select-file.ts b/packages/client/src/scripts/select-file.ts index 0c6bd7ccde..6019890444 100644 --- a/packages/client/src/scripts/select-file.ts +++ b/packages/client/src/scripts/select-file.ts @@ -1,8 +1,9 @@ import * as os from '@/os'; import { i18n } from '@/i18n'; import { defaultStore } from '@/store'; +import { DriveFile } from 'misskey-js/built/entities'; -export function selectFile(src: any, label: string | null, multiple = false) { +function select(src: any, label: string | null, multiple: boolean): Promise<DriveFile | DriveFile[]> { return new Promise((res, rej) => { const chooseFileFromPc = () => { const input = document.createElement('input'); @@ -86,3 +87,11 @@ export function selectFile(src: any, label: string | null, multiple = false) { }], src); }); } + +export function selectFile(src: any, label: string | null = null): Promise<DriveFile> { + return select(src, label, false) as Promise<DriveFile>; +} + +export function selectFiles(src: any, label: string | null = null): Promise<DriveFile[]> { + return select(src, label, true) as Promise<DriveFile[]>; +} diff --git a/packages/client/src/scripts/touch.ts b/packages/client/src/scripts/touch.ts new file mode 100644 index 0000000000..06b4f8b2ed --- /dev/null +++ b/packages/client/src/scripts/touch.ts @@ -0,0 +1,19 @@ +const isTouchSupported = 'maxTouchPoints' in navigator && navigator.maxTouchPoints > 0; + +export let isTouchUsing = false; + +export let isScreenTouching = false; + +if (isTouchSupported) { + window.addEventListener('touchstart', () => { + // maxTouchPointsなどでの判定だけだと、「タッチ機能付きディスプレイを使っているがマウスでしか操作しない」場合にも + // タッチで使っていると判定されてしまうため、実際に一度でもタッチされたらtrueにする + isTouchUsing = true; + + isScreenTouching = true; + }, { passive: true }); + + window.addEventListener('touchend', () => { + isScreenTouching = false; + }, { passive: true }); +} diff --git a/packages/client/src/scripts/use-tooltip.ts b/packages/client/src/scripts/use-tooltip.ts index a9bf6d93db..0df4baca7b 100644 --- a/packages/client/src/scripts/use-tooltip.ts +++ b/packages/client/src/scripts/use-tooltip.ts @@ -1,9 +1,16 @@ -import { isScreenTouching } from '@/os'; -import { Ref, ref } from 'vue'; -import { isDeviceTouch } from './is-device-touch'; +import { Ref, ref, watch } from 'vue'; -export function useTooltip(onShow: (showing: Ref<boolean>) => void) { +export function useTooltip( + elRef: Ref<HTMLElement | { $el: HTMLElement } | null | undefined>, + onShow: (showing: Ref<boolean>) => void, +): void { let isHovering = false; + + // iOS(Androidも?)では、要素をタップした直後に(おせっかいで)mouseoverイベントを発火させたりするため、それを無視するためのフラグ + // 無視しないと、画面に触れてないのにツールチップが出たりし、ユーザビリティが損なわれる + // TODO: 一度でもタップすると二度とマウスでツールチップ出せなくなるのをどうにかする 定期的にfalseに戻すとか...? + let shouldIgnoreMouseover = false; + let timeoutId: number; let changeShowingState: (() => void) | null; @@ -12,10 +19,6 @@ export function useTooltip(onShow: (showing: Ref<boolean>) => void) { close(); if (!isHovering) return; - // iOS(Androidも?)では、要素をタップした直後に(おせっかいで)mouseoverイベントを発火させたりするため、その対策 - // これが無いと、画面に触れてないのにツールチップが出たりしてしまう - if (isDeviceTouch && !isScreenTouching) return; - const showing = ref(true); onShow(showing); changeShowingState = () => { @@ -32,6 +35,7 @@ export function useTooltip(onShow: (showing: Ref<boolean>) => void) { const onMouseover = () => { if (isHovering) return; + if (shouldIgnoreMouseover) return; isHovering = true; timeoutId = window.setTimeout(open, 300); }; @@ -43,8 +47,31 @@ export function useTooltip(onShow: (showing: Ref<boolean>) => void) { close(); }; - return { - onMouseover, - onMouseleave, + const onTouchstart = () => { + shouldIgnoreMouseover = true; + if (isHovering) return; + isHovering = true; + timeoutId = window.setTimeout(open, 300); + }; + + const onTouchend = () => { + if (!isHovering) return; + isHovering = false; + window.clearTimeout(timeoutId); + close(); }; + + const stop = watch(elRef, () => { + if (elRef.value) { + stop(); + const el = elRef.value instanceof Element ? elRef.value : elRef.value.$el; + el.addEventListener('mouseover', onMouseover, { passive: true }); + el.addEventListener('mouseleave', onMouseleave, { passive: true }); + el.addEventListener('touchstart', onTouchstart, { passive: true }); + el.addEventListener('touchend', onTouchend, { passive: true }); + } + }, { + immediate: true, + flush: 'post', + }); } |