@wix/design-system
Version:
@wix/design-system
91 lines • 3.33 kB
JavaScript
import { useEffect, useRef, useCallback } from 'react';
import { useDragLayer } from 'react-dnd';
const SCROLL_ZONE_SIZE = 20;
const SCROLL_SPEED = 10;
const useDragLayerAutoScroll = (containerRef) => {
const { isDragging, currentOffset } = useDragLayer(monitor => ({
isDragging: monitor.isDragging(),
currentOffset: monitor.getClientOffset(),
}));
const animationFrame = useRef(null);
const getScrollContainer = useCallback(() => {
if (!containerRef || !containerRef.current) {
return window;
}
// Find scrollable parent
let node = containerRef.current.parentElement;
while (node && node !== document.body) {
const overflowY = window.getComputedStyle(node).overflowY;
const isScrollable = overflowY === 'auto' || overflowY === 'scroll';
if (isScrollable && node.scrollHeight > node.clientHeight) {
return node;
}
node = node.parentElement;
}
return window;
}, [containerRef]);
const scroll = useCallback(() => {
if (!isDragging || !currentOffset) {
animationFrame.current = requestAnimationFrame(scroll);
return;
}
const container = getScrollContainer();
if (!container) {
animationFrame.current = requestAnimationFrame(scroll);
return;
}
const { y } = currentOffset;
let scrollChange = 0;
if (container === window) {
const viewportHeight = window.innerHeight;
if (y < SCROLL_ZONE_SIZE) {
scrollChange = -SCROLL_SPEED;
}
else if (y > viewportHeight - SCROLL_ZONE_SIZE) {
scrollChange = SCROLL_SPEED;
}
if (scrollChange !== 0) {
window.scrollBy(0, scrollChange);
}
animationFrame.current = requestAnimationFrame(scroll);
}
else if (container instanceof HTMLElement) {
const rect = container.getBoundingClientRect();
if (y < rect.top + SCROLL_ZONE_SIZE) {
scrollChange = -SCROLL_SPEED;
}
else if (y > rect.bottom - SCROLL_ZONE_SIZE) {
scrollChange = SCROLL_SPEED;
}
if (scrollChange !== 0) {
container.scrollTop += scrollChange;
}
animationFrame.current = requestAnimationFrame(scroll);
}
}, [isDragging, currentOffset, getScrollContainer]);
useEffect(() => {
if (isDragging) {
animationFrame.current = requestAnimationFrame(scroll);
}
else {
if (animationFrame.current) {
cancelAnimationFrame(animationFrame.current);
animationFrame.current = null;
}
}
return () => {
if (animationFrame.current) {
cancelAnimationFrame(animationFrame.current);
animationFrame.current = null;
}
};
}, [isDragging, scroll]);
return null;
};
export { useDragLayerAutoScroll };
const AutoScroller = ({ containerRef }) => {
useDragLayerAutoScroll(containerRef);
return null;
};
export default AutoScroller;
//# sourceMappingURL=AutoScroller.js.map