Skip to content

Instantly share code, notes, and snippets.

@Zeko369
Last active July 3, 2023 13:26
Show Gist options
  • Save Zeko369/66cf4ea5915fd17f48ee9c7b2d3e60b1 to your computer and use it in GitHub Desktop.
Save Zeko369/66cf4ea5915fd17f48ee9c7b2d3e60b1 to your computer and use it in GitHub Desktop.
"use client";
import { useCallback, useRef } from "react";
import { css } from "../../../styled-system/css";
function useLongPress(
callback: (e: React.MouseEvent | React.TouchEvent) => void,
shortClick: () => void,
duration: number = 500
) {
// This will be a reference to our `setTimeout` counter, so we can clear it
// if the user moves or releases their pointer.
const timeout = useRef(null);
// Create an event handler for mouse down and touch start events. We wrap the
// handler in the `useCallback` hook and pass `callback` and `duration` as
// dependencies so it only creates a new callback if either of these changes.
const onPressStart = useCallback(
(event: React.MouseEvent | React.TouchEvent) => {
// Prevent the browser's default response to this event. On mobile browsers
// long presses are used . This will also block touch scrolling - a more
// robust implementation will take this into account, but this is fine
// for prototyping.
event.preventDefault();
// Start a timeout that, after the provided `duration`, will fire the
// supplied callbacl.
// @ts-ignore
timeout.current = setTimeout(() => {
callback(event);
timeout.current = null;
}, duration);
},
[callback, duration]
);
// This function, when called, will cancel the timeout and thus end the
// gesture. We provide an empty dependency array as we never want this
// function to change for the lifecycle of the component.
const cancelTimeout = useCallback((runcallback: boolean) => {
// @ts-ignore
clearTimeout(timeout.current);
runcallback && timeout.current && shortClick();
}, []);
return {
// Initiate the gesture on mouse down or touch start
onMouseDown: onPressStart,
onTouchStart: onPressStart,
// Cancel the gesture if the pointer is moved. This is quite an aggressive
// approach so you might want to make an alternative function here that
// detects how far the pointer has moved from its origin using `e.pageX`
// for `MouseEvent`s or `e.touches[0].pageX` for `TouchEvent`s.
onMouseMove: () => cancelTimeout(false),
onTouchMove: () => cancelTimeout(false),
// Cancel the timeout when the pointer session is ended.
onMouseUp: () => cancelTimeout(true),
onTouchEnd: () => cancelTimeout(true),
};
}
export default function Page() {
const handler = useLongPress(
(e) => {
console.log("Long press detected", e);
},
() => {
console.log("Short click");
}
);
return (
<button
{...handler}
className={css({
padding: 3,
backgroundColor: "#a3a3a3",
borderRadius: 4,
})}
>
Long press meeeee daddy
</button>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment