@mantine/hooks
Version:
A collection of 50+ hooks for state and UI management
102 lines (99 loc) • 3.43 kB
JavaScript
'use client';
import { useRef, useState, useEffect, useCallback } from 'react';
import { clamp } from '../utils/clamp/clamp.mjs';
function clampUseMovePosition(position) {
return {
x: clamp(position.x, 0, 1),
y: clamp(position.y, 0, 1)
};
}
function useMove(onChange, handlers, dir = "ltr") {
const mounted = useRef(false);
const isSliding = useRef(false);
const frame = useRef(0);
const [active, setActive] = useState(false);
useEffect(() => {
mounted.current = true;
}, []);
const refCallback = useCallback(
(node) => {
const onScrub = ({ x, y }) => {
cancelAnimationFrame(frame.current);
frame.current = requestAnimationFrame(() => {
if (mounted.current && node) {
node.style.userSelect = "none";
const rect = node.getBoundingClientRect();
if (rect.width && rect.height) {
const _x = clamp((x - rect.left) / rect.width, 0, 1);
onChange({
x: dir === "ltr" ? _x : 1 - _x,
y: clamp((y - rect.top) / rect.height, 0, 1)
});
}
}
});
};
const bindEvents = () => {
document.addEventListener("mousemove", onMouseMove);
document.addEventListener("mouseup", stopScrubbing);
document.addEventListener("touchmove", onTouchMove);
document.addEventListener("touchend", stopScrubbing);
};
const unbindEvents = () => {
document.removeEventListener("mousemove", onMouseMove);
document.removeEventListener("mouseup", stopScrubbing);
document.removeEventListener("touchmove", onTouchMove);
document.removeEventListener("touchend", stopScrubbing);
};
const startScrubbing = () => {
if (!isSliding.current && mounted.current) {
isSliding.current = true;
typeof handlers?.onScrubStart === "function" && handlers.onScrubStart();
setActive(true);
bindEvents();
}
};
const stopScrubbing = () => {
if (isSliding.current && mounted.current) {
isSliding.current = false;
setActive(false);
unbindEvents();
setTimeout(() => {
typeof handlers?.onScrubEnd === "function" && handlers.onScrubEnd();
}, 0);
}
};
const onMouseDown = (event) => {
startScrubbing();
event.preventDefault();
onMouseMove(event);
};
const onMouseMove = (event) => onScrub({ x: event.clientX, y: event.clientY });
const onTouchStart = (event) => {
if (event.cancelable) {
event.preventDefault();
}
startScrubbing();
onTouchMove(event);
};
const onTouchMove = (event) => {
if (event.cancelable) {
event.preventDefault();
}
onScrub({ x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY });
};
node?.addEventListener("mousedown", onMouseDown);
node?.addEventListener("touchstart", onTouchStart, { passive: false });
return () => {
if (node) {
node.removeEventListener("mousedown", onMouseDown);
node.removeEventListener("touchstart", onTouchStart);
}
};
},
[dir, onChange]
);
return { ref: refCallback, active };
}
export { clampUseMovePosition, useMove };
//# sourceMappingURL=use-move.mjs.map