126 lines
3.7 KiB
TypeScript
126 lines
3.7 KiB
TypeScript
'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,
|
|
};
|
|
}; |