From 0a38b0cd27f91f28fac18717ac1480d6e244f6d0 Mon Sep 17 00:00:00 2001 From: HF Date: Tue, 23 Jan 2024 23:44:55 +0100 Subject: [PATCH] create a react hook to deal with long presses on buttons --- src/components/hooks/useLongPress.js | 64 ++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 src/components/hooks/useLongPress.js diff --git a/src/components/hooks/useLongPress.js b/src/components/hooks/useLongPress.js new file mode 100644 index 00000000..3e13eab3 --- /dev/null +++ b/src/components/hooks/useLongPress.js @@ -0,0 +1,64 @@ +/* + * check for long presses of element + * return a function that can be attacked as ref to an element + */ + +import { useState, useRef, useCallback } from 'react'; + +function useLongPress(shortPressCallback, longPressCallback) { + const [pressTimeout, setPressTimeout] = useState(null); + const btnRef = useRef(); + + const press = useCallback((event) => { + event.preventDefault(); + setPressTimeout(setTimeout(() => { + longPressCallback(event); + setPressTimeout(null); + }, 600)); + }, [longPressCallback]); + + const release = useCallback((event) => { + event.preventDefault(); + if (!pressTimeout) { + // long press already occured + return; + } + clearTimeout(pressTimeout); + shortPressCallback(event); + setPressTimeout(null); + }, [pressTimeout, shortPressCallback]); + + const cancel = useCallback((event) => { + event.preventDefault(); + clearTimeout(pressTimeout); + setPressTimeout(null); + }, [pressTimeout]); + + const refCallback = useCallback((node) => { + if (!node) { + if (btnRef.current) { + const oldNode = btnRef.current; + // remove event listeners, happens on detach + oldNode.removeEventListener('mousedown', press, { passive: false }); + oldNode.removeEventListener('mouseup', release, { passive: false }); + oldNode.removeEventListener('touchstart', press, { passive: false }); + oldNode.removeEventListener('touchend', release, { passive: false }); + oldNode.removeEventListener('mouseleave', cancel, { passive: false }); + oldNode.removeEventListener('touchcancel', cancel, { passive: false }); + } + } else { + btnRef.current = node; + // add event listeners + node.addEventListener('mousedown', press, { passive: false }); + node.addEventListener('mouseup', release, { passive: false }); + node.addEventListener('touchstart', press, { passive: false }); + node.addEventListener('touchend', release, { passive: false }); + node.addEventListener('mouseleave', cancel, { passive: false }); + node.addEventListener('touchcancel', cancel, { passive: false }); + } + }, [cancel, press, release]); + + return refCallback; +} + +export default useLongPress;