ahooks
Version:
react hooks library
124 lines • 4.85 kB
JavaScript
import { useRef } from 'react';
import useLatest from '../useLatest';
import { getTargetElement } from '../utils/domTarget';
import isBrowser from '../utils/isBrowser';
import useEffectWithTarget from '../utils/useEffectWithTarget';
var touchSupported = isBrowser && (
// @ts-ignore
'ontouchstart' in window || window.DocumentTouch && document instanceof DocumentTouch);
function useLongPress(onLongPress, target, _a) {
var _b = _a === void 0 ? {} : _a,
_c = _b.delay,
delay = _c === void 0 ? 300 : _c,
moveThreshold = _b.moveThreshold,
onClick = _b.onClick,
onLongPressEnd = _b.onLongPressEnd;
var onLongPressRef = useLatest(onLongPress);
var onClickRef = useLatest(onClick);
var onLongPressEndRef = useLatest(onLongPressEnd);
var timerRef = useRef();
var isTriggeredRef = useRef(false);
var pervPositionRef = useRef({
x: 0,
y: 0
});
var hasMoveThreshold = !!((moveThreshold === null || moveThreshold === void 0 ? void 0 : moveThreshold.x) && moveThreshold.x > 0 || (moveThreshold === null || moveThreshold === void 0 ? void 0 : moveThreshold.y) && moveThreshold.y > 0);
useEffectWithTarget(function () {
var targetElement = getTargetElement(target);
if (!(targetElement === null || targetElement === void 0 ? void 0 : targetElement.addEventListener)) {
return;
}
var overThreshold = function (event) {
var _a = getClientPosition(event),
clientX = _a.clientX,
clientY = _a.clientY;
var offsetX = Math.abs(clientX - pervPositionRef.current.x);
var offsetY = Math.abs(clientY - pervPositionRef.current.y);
return !!((moveThreshold === null || moveThreshold === void 0 ? void 0 : moveThreshold.x) && offsetX > moveThreshold.x || (moveThreshold === null || moveThreshold === void 0 ? void 0 : moveThreshold.y) && offsetY > moveThreshold.y);
};
function getClientPosition(event) {
if (event instanceof TouchEvent) {
return {
clientX: event.touches[0].clientX,
clientY: event.touches[0].clientY
};
}
if (event instanceof MouseEvent) {
return {
clientX: event.clientX,
clientY: event.clientY
};
}
console.warn('Unsupported event type');
return {
clientX: 0,
clientY: 0
};
}
var onStart = function (event) {
if (hasMoveThreshold) {
var _a = getClientPosition(event),
clientX = _a.clientX,
clientY = _a.clientY;
pervPositionRef.current.x = clientX;
pervPositionRef.current.y = clientY;
}
timerRef.current = setTimeout(function () {
onLongPressRef.current(event);
isTriggeredRef.current = true;
}, delay);
};
var onMove = function (event) {
if (timerRef.current && overThreshold(event)) {
clearTimeout(timerRef.current);
timerRef.current = undefined;
}
};
var onEnd = function (event, shouldTriggerClick) {
var _a;
if (shouldTriggerClick === void 0) {
shouldTriggerClick = false;
}
if (timerRef.current) {
clearTimeout(timerRef.current);
}
if (isTriggeredRef.current) {
(_a = onLongPressEndRef.current) === null || _a === void 0 ? void 0 : _a.call(onLongPressEndRef, event);
}
if (shouldTriggerClick && !isTriggeredRef.current && onClickRef.current) {
onClickRef.current(event);
}
isTriggeredRef.current = false;
};
var onEndWithClick = function (event) {
return onEnd(event, true);
};
if (!touchSupported) {
targetElement.addEventListener('mousedown', onStart);
targetElement.addEventListener('mouseup', onEndWithClick);
targetElement.addEventListener('mouseleave', onEnd);
if (hasMoveThreshold) targetElement.addEventListener('mousemove', onMove);
} else {
targetElement.addEventListener('touchstart', onStart);
targetElement.addEventListener('touchend', onEndWithClick);
if (hasMoveThreshold) targetElement.addEventListener('touchmove', onMove);
}
return function () {
if (timerRef.current) {
clearTimeout(timerRef.current);
isTriggeredRef.current = false;
}
if (!touchSupported) {
targetElement.removeEventListener('mousedown', onStart);
targetElement.removeEventListener('mouseup', onEndWithClick);
targetElement.removeEventListener('mouseleave', onEnd);
if (hasMoveThreshold) targetElement.removeEventListener('mousemove', onMove);
} else {
targetElement.removeEventListener('touchstart', onStart);
targetElement.removeEventListener('touchend', onEndWithClick);
if (hasMoveThreshold) targetElement.removeEventListener('touchmove', onMove);
}
};
}, [], target);
}
export default useLongPress;