@mantine/hooks
Version:
A collection of 50+ hooks for state and UI management
132 lines (131 loc) • 4.58 kB
JavaScript
"use client";
let react = require("react");
//#region packages/@mantine/hooks/src/use-scroller/use-scroller.ts
function useScroller(options = {}) {
const { scrollAmount = 200, draggable = true, onScrollStateChange } = options;
const containerRef = (0, react.useRef)(null);
const [canScrollStart, setCanScrollStart] = (0, react.useState)(false);
const [canScrollEnd, setCanScrollEnd] = (0, react.useState)(false);
const [isDragging, setIsDragging] = (0, react.useState)(false);
const isDraggingRef = (0, react.useRef)(false);
const hasDraggedRef = (0, react.useRef)(false);
const startX = (0, react.useRef)(0);
const scrollLeftStart = (0, react.useRef)(0);
const onScrollStateChangeRef = (0, react.useRef)(onScrollStateChange);
onScrollStateChangeRef.current = onScrollStateChange;
const updateScrollState = (0, react.useCallback)(() => {
const container = containerRef.current;
if (container) {
const { scrollLeft, scrollWidth, clientWidth } = container;
const isRtl = getComputedStyle(container).direction === "rtl";
let newCanScrollStart;
let newCanScrollEnd;
if (isRtl) {
newCanScrollStart = scrollLeft < 0;
newCanScrollEnd = scrollLeft > -(scrollWidth - clientWidth);
} else {
newCanScrollStart = scrollLeft > 0;
newCanScrollEnd = scrollLeft < scrollWidth - clientWidth - 1;
}
setCanScrollStart(newCanScrollStart);
setCanScrollEnd(newCanScrollEnd);
onScrollStateChangeRef.current?.({
canScrollStart: newCanScrollStart,
canScrollEnd: newCanScrollEnd
});
}
}, []);
(0, react.useEffect)(() => {
updateScrollState();
const container = containerRef.current;
if (container) {
container.addEventListener("scroll", updateScrollState);
const resizeObserver = new ResizeObserver(updateScrollState);
resizeObserver.observe(container);
return () => {
container.removeEventListener("scroll", updateScrollState);
resizeObserver.disconnect();
};
}
}, [updateScrollState]);
const scroll = (0, react.useCallback)((direction) => {
const container = containerRef.current;
if (container) {
const isRtl = getComputedStyle(container).direction === "rtl";
const amount = scrollAmount;
const scrollBy = direction === "end" ? amount : -amount;
const adjustedScrollBy = isRtl ? -scrollBy : scrollBy;
container.scrollBy({
left: adjustedScrollBy,
behavior: "smooth"
});
}
}, [scrollAmount]);
const scrollStart = (0, react.useCallback)(() => scroll("start"), [scroll]);
const scrollEnd = (0, react.useCallback)(() => scroll("end"), [scroll]);
const handleMouseDown = (0, react.useCallback)((event) => {
if (!draggable) return;
const container = containerRef.current;
if (container) {
isDraggingRef.current = true;
hasDraggedRef.current = false;
setIsDragging(true);
startX.current = event.pageX - container.offsetLeft;
scrollLeftStart.current = container.scrollLeft;
container.style.cursor = "grabbing";
container.style.userSelect = "none";
}
}, [draggable]);
const handleMouseMove = (0, react.useCallback)((event) => {
if (!isDraggingRef.current) return;
event.preventDefault();
const container = containerRef.current;
if (container) {
const walk = event.pageX - container.offsetLeft - startX.current;
if (Math.abs(walk) > 5) hasDraggedRef.current = true;
container.scrollLeft = scrollLeftStart.current - walk;
}
}, []);
const handleMouseUp = (0, react.useCallback)(() => {
const wasDragged = hasDraggedRef.current;
isDraggingRef.current = false;
hasDraggedRef.current = false;
setIsDragging(false);
const container = containerRef.current;
if (container) {
container.style.cursor = "";
container.style.userSelect = "";
if (wasDragged) {
const suppressClick = (event) => {
event.stopPropagation();
event.preventDefault();
container.removeEventListener("click", suppressClick, true);
};
container.addEventListener("click", suppressClick, true);
}
}
}, []);
const handleMouseLeave = (0, react.useCallback)(() => {
if (isDraggingRef.current) handleMouseUp();
}, [handleMouseUp]);
return {
ref: (0, react.useCallback)((node) => {
containerRef.current = node;
if (node) updateScrollState();
}, [updateScrollState]),
canScrollStart,
canScrollEnd,
scrollStart,
scrollEnd,
isDragging,
dragHandlers: {
onMouseDown: handleMouseDown,
onMouseMove: handleMouseMove,
onMouseUp: handleMouseUp,
onMouseLeave: handleMouseLeave
}
};
}
//#endregion
exports.useScroller = useScroller;
//# sourceMappingURL=use-scroller.cjs.map