craft.js
craft.js copied to clipboard
Auto scroll to the top of the page does not work while dragging an element
Describe the bug Auto scroll to the top of the page does not work while dragging an element.
To Reproduce Steps to reproduce the behavior:
- Go to (https://craft.js.org/examples/landing/).
- Scroll to the bottom of the page.
- Start dragging any element from the end.
- Try to go with that element on top.
Expected behavior In this video below I would expect an auto-scroll to the top of the page.
Video Demonstration See the video (see expected behavior above) https://www.loom.com/share/984feca6f62448d6b051653aa3b6a375
Hi @prevwong! I think you will directly have an idea what the solution could be. Can you give us a hint? Thanks in advance :)
There is nothing I can see to tell to scroll, looking into the code it seems one would need to replicate a drag handler, check scrolling conditions, and scroll the window (or dom element).
https://github.com/prevwong/craft.js/blob/993a6bf49c54c97a0ab1959ac151e64d64b1ca4c/packages/layers/src/events/LayerHandlers.ts
I implement my own scroll behavior while dragging.
Viewport.ts
import { throttle } from '../../helper/throttle';
import useWindowDimensions from '../../hooks/useWindowDimensions';
export const Viewport: React.FC = ({ children }) => {
const step = 1;
const scrollRef = useRef<Element | null>(null);
const isScrollRef = useRef<boolean>(false);
const { height } = useWindowDimensions();
const setMove = (state: boolean) => {
isScrollRef.current = state;
};
const moveToTop = () => {
if (scrollRef.current?.scrollTop && isScrollRef.current) {
scrollRef.current.scrollTop = scrollRef.current.scrollTop - step;
requestAnimationFrame(moveToTop);
}
};
const moveToBottom = () => {
if (
(scrollRef.current?.scrollTop === 0 || scrollRef.current?.scrollTop) &&
isScrollRef.current
) {
scrollRef.current.scrollTop = scrollRef.current.scrollTop + step;
requestAnimationFrame(moveToBottom);
}
};
const throttledMoveToTop = useRef(throttle(moveToTop, 100)).current;
const throttledMoveToBottom = useRef(throttle(moveToBottom, 100)).current;
useEffect(() => {
scrollRef.current = document.getElementsByClassName('builder__content')[0];
document.addEventListener(
'drag',
function(e) {
e = e || window.event;
const dragY = e.pageY;
//Distance from bottom less then 50px
if (dragY > height - 50) {
setMove(true);
throttledMoveToBottom();
} else if (dragY < 100) {
setMove(true);
throttledMoveToTop();
} else {
setMove(false);
}
},
false
);
document.addEventListener(
'dragend',
function(e) {
setMove(false);
},
false
);
}, []);
return (
<div className="page-container">
<div className={'craftjs-renderer'}>{children}</div>
</div>
);
};
throttle.ts
let inThrottle: boolean;
return function(this: any) {
const args: any = arguments;
const context = this;
if (!inThrottle) {
func.apply(context, args);
inThrottle = true;
setTimeout(() => (inThrottle = false), limit);
}
};
};
useWindowDimensions.ts
function getWindowDimensions() {
const { innerWidth: width, innerHeight: height } = window;
return {
width,
height
};
}
export default function useWindowDimensions() {
const [windowDimensions, setWindowDimensions] = useState(getWindowDimensions());
useEffect(() => {
function handleResize() {
setWindowDimensions(getWindowDimensions());
}
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return windowDimensions;
}
Thanks for sharing this @AminRafaey !