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