woedii/hooks/useContextMenuTriggers.ts

126 lines
3.7 KiB
TypeScript
Raw Normal View History

'use client'
import { useRef, useCallback, useState } from 'react';
interface UseContextMenuTriggersProps {
longPressDelay?: number;
doubleClickDelay?: number;
onLongPress?: () => void;
onDoubleTap?: () => void;
}
export const useContextMenuTriggers = ({
longPressDelay = 500, // Default long press delay in ms
doubleClickDelay = 300, // Default double click delay in ms
onLongPress,
onDoubleTap
}: UseContextMenuTriggersProps = {}) => {
const [isLongPressing, setIsLongPressing] = useState(false);
const longPressTimerRef = useRef<NodeJS.Timeout | null>(null);
const lastClickTimeRef = useRef<number>(0);
const targetRef = useRef<HTMLElement | null>(null);
const preventClickRef = useRef<boolean>(false);
// Function to simulate a right-click event
const simulateRightClick = useCallback((element: HTMLElement) => {
console.log("Simulating right click");
// Create and dispatch a custom contextmenu event
const contextMenuEvent = new MouseEvent('contextmenu', {
bubbles: true,
cancelable: true,
clientX: element.getBoundingClientRect().left + element.offsetWidth / 2,
clientY: element.getBoundingClientRect().top + element.offsetHeight / 2,
});
element.dispatchEvent(contextMenuEvent);
}, []);
// Handle touch start (for long press)
const handleTouchStart = useCallback((e: React.TouchEvent) => {
console.log("Touch start detected");
if (e.touches.length === 1) {
const element = e.currentTarget as HTMLElement;
targetRef.current = element;
// Clear any existing timer
if (longPressTimerRef.current) {
clearTimeout(longPressTimerRef.current);
}
setIsLongPressing(true);
preventClickRef.current = false;
// Start a timer for long press
longPressTimerRef.current = setTimeout(() => {
if (targetRef.current) {
console.log("Long press detected");
preventClickRef.current = true;
if (onLongPress) {
onLongPress();
} else {
simulateRightClick(targetRef.current);
}
}
}, longPressDelay);
}
}, [longPressDelay, simulateRightClick, onLongPress]);
// Handle touch end (cancel long press)
const handleTouchEnd = useCallback(() => {
console.log("Touch end detected");
if (longPressTimerRef.current) {
clearTimeout(longPressTimerRef.current);
}
setIsLongPressing(false);
}, []);
// Handle touch move (cancel long press if moving)
const handleTouchMove = useCallback(() => {
console.log("Touch move detected");
if (longPressTimerRef.current) {
clearTimeout(longPressTimerRef.current);
}
setIsLongPressing(false);
}, []);
// Handle click and double click/tap
const handleClick = useCallback((e: React.MouseEvent) => {
if (preventClickRef.current) {
preventClickRef.current = false;
return;
}
const currentTime = new Date().getTime();
const element = e.currentTarget as HTMLElement;
// Check if this is a double click
if (currentTime - lastClickTimeRef.current < doubleClickDelay) {
console.log("Double tap detected");
// Double click detected
if (onDoubleTap) {
onDoubleTap();
} else {
simulateRightClick(element);
}
lastClickTimeRef.current = 0; // Reset to prevent triple-click issues
} else {
// First click
console.log("Single tap detected");
lastClickTimeRef.current = currentTime;
}
}, [doubleClickDelay, simulateRightClick, onDoubleTap]);
return {
handlers: {
onTouchStart: handleTouchStart,
onTouchEnd: handleTouchEnd,
onTouchMove: handleTouchMove,
onClick: handleClick,
},
simulateRightClick,
};
};