UNPKG

@wix/design-system

Version:

@wix/design-system

100 lines 3.7 kB
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(() => { const startNode = containerRef && containerRef.current; if (!startNode) { return window; } // The virtualized container is itself the scroller, so check the ref node // before walking up. Non-virtualized renders an unscrolled wrapper here, // so the walk falls through to an ancestor scroller (or window) as before. const isScrollable = (el) => { const { overflowY } = window.getComputedStyle(el); return ((overflowY === 'auto' || overflowY === 'scroll') && el.scrollHeight > el.clientHeight); }; if (isScrollable(startNode)) { return startNode; } let node = startNode.parentElement; while (node && node !== document.body) { if (isScrollable(node)) { 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