add long press to card controls for shuffle

This commit is contained in:
jeffvli
2025-11-23 15:58:36 -08:00
parent 1763f666b5
commit db110733a4
2 changed files with 182 additions and 27 deletions
+103 -2
View File
@@ -1,3 +1,104 @@
import { useLongPress as useMantineLongPress } from '@mantine/hooks';
import { useCallback, useRef } from 'react';
export const useLongPress = useMantineLongPress;
interface UseLongPressOptions<T extends HTMLElement = HTMLElement> {
delay?: number;
onClick?: (event: React.MouseEvent<T> | React.TouchEvent<T>) => void;
onLongPress?: (event: React.MouseEvent<T> | React.TouchEvent<T>) => void;
}
interface UseLongPressReturn {
onMouseDown: (event: React.MouseEvent) => void;
onMouseLeave: (event: React.MouseEvent) => void;
onMouseUp: (event: React.MouseEvent) => void;
onTouchCancel: (event: React.TouchEvent) => void;
onTouchEnd: (event: React.TouchEvent) => void;
onTouchStart: (event: React.TouchEvent) => void;
}
export const useLongPress = <T extends HTMLElement = HTMLElement>({
delay = 500,
onClick,
onLongPress,
}: UseLongPressOptions<T>): UseLongPressReturn => {
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
const targetRef = useRef<EventTarget | null>(null);
const longPressTriggeredRef = useRef(false);
const eventRef = useRef<null | React.MouseEvent<T> | React.TouchEvent<T>>(null);
const start = useCallback(
(event: React.MouseEvent<T> | React.TouchEvent<T>) => {
longPressTriggeredRef.current = false;
targetRef.current = event.target;
eventRef.current = event;
timeoutRef.current = setTimeout(() => {
longPressTriggeredRef.current = true;
if (eventRef.current) {
onLongPress?.(eventRef.current);
}
}, delay);
},
[onLongPress, delay],
);
const clear = useCallback(() => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
timeoutRef.current = null;
}
}, []);
const handleMouseDown = useCallback(
(event: React.MouseEvent) => {
event.preventDefault();
start(event as React.MouseEvent<T>);
},
[start],
);
const handleMouseUp = useCallback(() => {
clear();
if (!longPressTriggeredRef.current && onClick && eventRef.current) {
onClick(eventRef.current);
}
longPressTriggeredRef.current = false;
eventRef.current = null;
}, [clear, onClick]);
const handleMouseLeave = useCallback(() => {
clear();
longPressTriggeredRef.current = false;
eventRef.current = null;
}, [clear]);
const handleTouchStart = useCallback(
(event: React.TouchEvent) => {
start(event as React.TouchEvent<T>);
},
[start],
);
const handleTouchEnd = useCallback(() => {
clear();
if (!longPressTriggeredRef.current && onClick && eventRef.current) {
onClick(eventRef.current);
}
longPressTriggeredRef.current = false;
eventRef.current = null;
}, [clear, onClick]);
const handleTouchCancel = useCallback(() => {
clear();
longPressTriggeredRef.current = false;
eventRef.current = null;
}, [clear]);
return {
onMouseDown: handleMouseDown,
onMouseLeave: handleMouseLeave,
onMouseUp: handleMouseUp,
onTouchCancel: handleTouchCancel,
onTouchEnd: handleTouchEnd,
onTouchStart: handleTouchStart,
};
};