import { RefObject, useCallback, useEffect, useRef } from 'react'; import { useMediaQuery } from './useMediaQuery'; const RECENT_MS = 700; /** * [Gitea #147] Tells whether a click was produced by a finger. Records the * last touch inside `ref`; `wasTouch()` is true for a short window after it. * Keyboard activation and screen-reader activation (TalkBack/VoiceOver send a * bare click, no touch events) report false, so they keep one-step behaviour. * Always false on devices without a coarse pointer. */ export function useRecentTouch(ref: RefObject) { const coarse = useMediaQuery('(pointer: coarse)'); const last = useRef(0); // Listen on the document (the ref'd element may be remounted, e.g. on a tab // switch) and only count touches that land inside it. useEffect(() => { if (!coarse) return undefined; const mark = (evt: TouchEvent) => { const el = ref.current; if (el && evt.target instanceof Node && !el.contains(evt.target)) return; last.current = Date.now(); }; document.addEventListener('touchstart', mark, { passive: true, capture: true }); document.addEventListener('touchend', mark, { passive: true, capture: true }); return () => { document.removeEventListener('touchstart', mark, { capture: true }); document.removeEventListener('touchend', mark, { capture: true }); }; }, [ref, coarse]); const wasTouch = useCallback(() => coarse && Date.now() - last.current < RECENT_MS, [coarse]); return { coarse, wasTouch }; }