useLongPress.ts 1.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546
  1. import { useCallback, useRef } from 'react';
  2. interface LongPressOptions {
  3. onLongPress: (e: React.TouchEvent | React.MouseEvent) => void;
  4. onClick?: () => void;
  5. delay?: number;
  6. }
  7. export function useLongPress({ onLongPress, onClick, delay = 500 }: LongPressOptions) {
  8. const timeoutRef = useRef<number | null>(null);
  9. const targetRef = useRef<EventTarget | null>(null);
  10. const longPressTriggered = useRef(false);
  11. const start = useCallback(
  12. (e: React.TouchEvent | React.MouseEvent) => {
  13. longPressTriggered.current = false;
  14. targetRef.current = e.target;
  15. timeoutRef.current = window.setTimeout(() => {
  16. longPressTriggered.current = true;
  17. onLongPress(e);
  18. }, delay);
  19. },
  20. [onLongPress, delay]
  21. );
  22. const clear = useCallback(
  23. (e: React.TouchEvent | React.MouseEvent, shouldTriggerClick = true) => {
  24. if (timeoutRef.current) {
  25. clearTimeout(timeoutRef.current);
  26. timeoutRef.current = null;
  27. }
  28. if (shouldTriggerClick && !longPressTriggered.current && onClick && targetRef.current === e.target) {
  29. onClick();
  30. }
  31. },
  32. [onClick]
  33. );
  34. return {
  35. onMouseDown: start,
  36. onMouseUp: (e: React.MouseEvent) => clear(e, true),
  37. onMouseLeave: (e: React.MouseEvent) => clear(e, false),
  38. onTouchStart: start,
  39. onTouchEnd: (e: React.TouchEvent) => clear(e, true),
  40. };
  41. }