react-dnd-scrolling
react-dnd-scrolling copied to clipboard
Apply scrolling behaviour to viewport
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 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>
);
}
}
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?
@ttt43ttt i need same feature as @paul-mesnilgrente wants. Please help us
@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 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 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?
@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.
@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
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 here you are: https://codesandbox.io/s/react-dnd-scrolling-demo-forked-98ubm
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 appreciate it if you can raise a PR
@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.
https://github.com/TechStark/react-dnd-scrolling/pull/7 I'm hitting an issue running the example. Help would be appreciated :)
@paul-mesnilgrente here you are: https://codesandbox.io/s/react-dnd-scrolling-demo-forked-98ubm
This is brilliant, thank you 👏
@mamadoo The speed of scrolling is keep increasing after we drag and drop 2-3 times. Do you know why this issue is occur. ?