Is your feature request related to a problem? Please describe.
useViewportScroll only works with the body element.
Describe the solution you'd like
I'd like if useViewportScroll could optionally accept a ref to an element and use the closest scroll container.
Describe alternatives you've considered
I noticed that the docs suggest rolling this yourself, but I think it could be helpful to provide out of the box.
I'd be happy to submit a PR with this functionality, please let me know 馃槉.
Yeah we鈥檇 take a PR for this!
Awesome! I should be able to get something together tomorrow 馃榿
I've also ended up needing this feature. If help is needed with the PR I'm happy to chip in.
Is anything happening with this, really need this
Or: is there away to do this manually @souporserious @InventingWithMonster ?
Edit: Did not see the work done with this PR and this PR, but I'll just leave my answer here anyway.
You could do something like this, inspired by the the source.
export function useViewportScrollForElement(element) {
const viewportMotionValues = {
scrollX: motionValue(0),
scrollY: motionValue(0),
scrollXProgress: motionValue(0),
scrollYProgress: motionValue(0)
};
const setProgress = (offset, maxOffset, value) => {
value.set(!maxOffset || !offset ? 0 : offset / maxOffset);
};
const hasEventListenerRef = useRef(false);
useEffect(() => {
if (!element) return;
const updateScrollValues = () => {
window.requestAnimationFrame(() => {
const xOffset = element.scrollLeft;
const yOffset = element.scrollTop;
// Set absolute positions
viewportMotionValues.scrollX.set(xOffset);
viewportMotionValues.scrollY.set(yOffset);
// Set 0-1 progress
setProgress(
xOffset,
element.clientWidth - element.clientHeight,
viewportMotionValues.scrollXProgress
);
setProgress(
yOffset,
element.scrollHeight - element.clientHeight,
viewportMotionValues.scrollYProgress
);
});
};
if (!hasEventListenerRef.current) {
hasEventListenerRef.current = true;
if (typeof window === "undefined") return;
updateScrollValues();
window.addEventListener("resize", updateScrollValues);
window.addEventListener("scroll", updateScrollValues, true);
}
return () => {
hasEventListenerRef.current = false;
window.removeEventListener("resize", updateScrollValues);
window.removeEventListener("scroll", updateScrollValues, true);
};
}, [element, viewportMotionValues]);
return viewportMotionValues;
}
And use it like this for example:
const { scrollYProgress } = useViewportScroll(scrollRef.current || document.getElementById('scroll-container'));
Regarding getting the nearest scrollcontainer this code can be used with this scrollparent npm package.
Keep in mind I haven't thoroughly tested the code, but it works so far for my needs.
Most helpful comment
I've also ended up needing this feature. If help is needed with the PR I'm happy to chip in.