woedii/hooks/useContextMenuTriggers.ts

96 lines
3.0 KiB
TypeScript
Raw Normal View History

'use client'
import { useRef, useCallback, useState } from 'react';
interface UseContextMenuTriggersProps {
longPressDelay?: number;
doubleClickDelay?: number;
}
export const useContextMenuTriggers = ({
longPressDelay = 500, // Default long press delay in ms
doubleClickDelay = 300, // Default double click delay in ms
}: UseContextMenuTriggersProps = {}) => {
const [isLongPressing, setIsLongPressing] = useState(false);
const longPressTimerRef = useRef<NodeJS.Timeout | null>(null);
const lastClickTimeRef = useRef<number>(0);
const targetRef = useRef<HTMLElement | null>(null);
// Function to simulate a right-click event
const simulateRightClick = useCallback((element: HTMLElement) => {
// 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) => {
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);
// Start a timer for long press
longPressTimerRef.current = setTimeout(() => {
if (isLongPressing && targetRef.current) {
simulateRightClick(targetRef.current);
}
}, longPressDelay);
}
}, [longPressDelay, isLongPressing, simulateRightClick]);
// Handle touch end (cancel long press)
const handleTouchEnd = useCallback(() => {
if (longPressTimerRef.current) {
clearTimeout(longPressTimerRef.current);
}
setIsLongPressing(false);
}, []);
// Handle touch move (cancel long press if moving)
const handleTouchMove = useCallback(() => {
if (longPressTimerRef.current) {
clearTimeout(longPressTimerRef.current);
}
setIsLongPressing(false);
}, []);
// Handle double click
const handleClick = useCallback((e: React.MouseEvent) => {
const currentTime = new Date().getTime();
const element = e.currentTarget as HTMLElement;
// Check if this is a double click
if (currentTime - lastClickTimeRef.current < doubleClickDelay) {
// Double click detected
simulateRightClick(element);
lastClickTimeRef.current = 0; // Reset to prevent triple-click issues
} else {
// First click
lastClickTimeRef.current = currentTime;
}
}, [doubleClickDelay, simulateRightClick]);
return {
handlers: {
onTouchStart: handleTouchStart,
onTouchEnd: handleTouchEnd,
onTouchMove: handleTouchMove,
onClick: handleClick,
},
simulateRightClick,
};
};