react-dnd-scrolling icon indicating copy to clipboard operation
react-dnd-scrolling copied to clipboard

Apply scrolling behaviour to viewport

Open paul-mesnilgrente opened this issue 3 years ago • 16 comments

Hi,

I am looking into this kind of behavior but applied to the viewport instead of a DOM element. Or there's a way to create "an invisible" DOM element which could be used to scroll?

The thing is, I have many blocks in the page but they are not constrained in height. Is it possible to have scrolling when the dragged item reaches the top/bottom of the viewport?

paul-mesnilgrente avatar Aug 02 '21 14:08 paul-mesnilgrente

@paul-mesnilgrente you can make the scroll container's size same as the viewport, e.g. set height to 100vh.

const ScrollingComponent = withScrolling('div');

const ITEMS = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 , 12, 14, 15, 19, 20, 21, 22, 23];

export default class App extends Component {
  render() {
    return (
      <DndProvider backend={HTML5Backend}>
        <ScrollingComponent style={{
	      height: 100vh;
	      width: 100vw;
	      overflow: auto;
		}}>
          <div className="App">
            {ITEMS.map(n => (
              <DragItem key={n} label={`Item ${n}`} />
            ))}
          </div>
        </ScrollingComponent>
      </DndProvider>
    );
  }
}

ttt43ttt avatar Aug 09 '21 05:08 ttt43ttt

This solution creates a scrollbar which looks pretty ugly and it's also not part of the intended UX. So the answer looks to be that you don't fully support it. Is there any plan to support this?

paul-mesnilgrente avatar Aug 10 '21 19:08 paul-mesnilgrente

@ttt43ttt i need same feature as @paul-mesnilgrente wants. Please help us

mamadoo avatar Aug 11 '21 07:08 mamadoo

@paul-mesnilgrente I wrote this code for my problem. what's your opinion?

filename: useDragScrolling.js

import { useRef } from "react";
import { throttle } from "lodash";

const useDragScrolling = () => {
  const isScrolling = useRef(false);

  const goDown = () => {
    document.documentElement.scrollTop += 6;

    const { offsetHeight, scrollTop, scrollHeight } = document.documentElement;
    const isScrollEnd = offsetHeight + scrollTop >= scrollHeight;

    if (isScrolling.current && !isScrollEnd) {
      window.requestAnimationFrame(goDown);
    }
  };

  const goUp = () => {
    document.documentElement.scrollTop -= 6;

    if (isScrolling.current && window.scrollY > 0) {
      window.requestAnimationFrame(goUp);
    }
  };

  const onDragOver = (event) => {
    const isMouseOnTop = event.clientY < 50;
    const isMouseOnDown = window.innerHeight - event.clientY < 50;

    if (!isScrolling.current && (isMouseOnTop || isMouseOnDown)) {
      isScrolling.current = true;

      if (isMouseOnTop) {
        window.requestAnimationFrame(goUp);
      }

      if (isMouseOnDown) {
        window.requestAnimationFrame(goDown);
      }
    } else if (!isMouseOnTop && !isMouseOnDown) {
      isScrolling.current = false;
    }
  };

  const throttleOnDragOver = throttle(onDragOver, 300);

  const addEventListenerForWindow = () => {
    window.addEventListener("dragover", throttleOnDragOver, false);
  };

  const removeEventListenerForWindow = () => {
    window.removeEventListener("dragover", throttleOnDragOver, false);
    isScrolling.current = false;
  };

  return {
    addEventListenerForWindow,
    removeEventListenerForWindow,
  };
};

export default useDragScrolling;

and use it like below:

const [{ isDragging }, drag, preview] = useDrag(() => ({
    type: dragTypes.Letter,
    item: () => {
      addEventListenerForWindow();
      return {
        id,
      };
    },
    end: () => {
      removeEventListenerForWindow();
    },
  }));

mamadoo avatar Aug 11 '21 13:08 mamadoo

@mamadoo is this working ready to run? I don't understand how you use the useDragScrolling function. I see you use directly the addEventListenerForWindow and removeEventListenerForWindow.

The idea looks pretty good otherwise. It would be better if the library was implementing something like this instead as you re-implement most of what the library is doing already.

I'm keen to see a working example with what you've done anyway.

paul-mesnilgrente avatar Aug 12 '21 13:08 paul-mesnilgrente

@paul-mesnilgrente I made a little style change to my earlier comment. Also created a page here https://codesandbox.io/s/cranky-mountain-vnp66 Can you see if it works for you?

ttt43ttt avatar Aug 12 '21 14:08 ttt43ttt

@paul-mesnilgrente my solution doesn't rely to package "react-dnd-scrolling" and i use it for solving problems in my app. So you can use this code or the owner of package should implement such a thing to support this behavior.

mamadoo avatar Aug 14 '21 05:08 mamadoo

@ttt43ttt your example doesn't work in my use case. See the fixed height of the .App creating this scroll bar on the left of the .App container, I don't want that. Also my items are spaced out. I created a fork of your example: https://codesandbox.io/s/react-dnd-scrolling-demo-forked-0q0ru. In that example, try to drag an item and to scroll the window at the same time. It's pretty hard! Specially in Firefox.

@mamadoo I'll try your example

paul-mesnilgrente avatar Aug 16 '21 14:08 paul-mesnilgrente

Actually @mamadoo, do you think you can have your example working on this example https://codesandbox.io/s/react-dnd-scrolling-demo-forked-0q0ru ? I'm struggling to implement it :/

paul-mesnilgrente avatar Aug 16 '21 14:08 paul-mesnilgrente

@paul-mesnilgrente here you are: https://codesandbox.io/s/react-dnd-scrolling-demo-forked-98ubm

mamadoo avatar Aug 17 '21 06:08 mamadoo

Ah yeah, looks pretty good, scrolling down doesn't work on my Firefox for some reasons but I think I could figure this out.

Looks like this PR is doing pretty much what you're doing: https://github.com/azuqua/react-dnd-scrollzone/pull/20/files. Doesn't it?

I'll try to test this out. Are you interested in merging a similar PR @TechStark?

paul-mesnilgrente avatar Aug 17 '21 15:08 paul-mesnilgrente

@paul-mesnilgrente appreciate it if you can raise a PR

ttt43ttt avatar Aug 17 '21 15:08 ttt43ttt

@paul-mesnilgrente i think that PR is a solution but not merged and can't be tested. But i think the owner of main package doesn't like to implement this feature. react-beautiful-dnd support this feature by default but we could use react-beautiful-dnd in limited scenarios like lists and etc.

mamadoo avatar Aug 17 '21 16:08 mamadoo

https://github.com/TechStark/react-dnd-scrolling/pull/7 I'm hitting an issue running the example. Help would be appreciated :)

paul-mesnilgrente avatar Aug 17 '21 16:08 paul-mesnilgrente

@paul-mesnilgrente here you are: https://codesandbox.io/s/react-dnd-scrolling-demo-forked-98ubm

This is brilliant, thank you 👏

dooleyb1 avatar Nov 24 '21 10:11 dooleyb1

@mamadoo The speed of scrolling is keep increasing after we drag and drop 2-3 times. Do you know why this issue is occur. ?

pranavmappoli avatar Jan 17 '23 14:01 pranavmappoli