Skip to content

Instantly share code, notes, and snippets.

@smashercosmo
Created November 27, 2020 12:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save smashercosmo/0141e11ac7cbfe21ee979f629cf3083b to your computer and use it in GitHub Desktop.
Save smashercosmo/0141e11ac7cbfe21ee979f629cf3083b to your computer and use it in GitHub Desktop.
useDragScroll
import * as React from 'react'
import { useDrag } from 'react-use-gesture'
import { useSpring, config } from '@react-spring/web'
function clamp(min: number, val: number, max: number) {
return Math.min(Math.max(min, val), max)
}
const isServer = typeof window === 'undefined'
function useDragScroll() {
const scrollX = isServer ? 0 : window.scrollX
const scrollY = isServer ? 0 : window.scrollY
const isMouseAction = React.useRef(false)
const [values] = useSpring(
{
from: {
x: scrollX,
y: scrollY,
},
onChange: {
x(value: number) {
document.documentElement.scrollLeft = value
},
y(value: number) {
document.documentElement.scrollTop = value
},
},
config: config.slow,
},
[],
)
function setX(value: number) {
const minScrollLeft = 0
const maxScrollLeft =
document.documentElement.scrollWidth -
document.documentElement.clientWidth
const to = clamp(minScrollLeft, values.x.goal + value, maxScrollLeft)
values.x.start({ to })
}
function setY(value: number) {
const minScrollTop = 0
const maxScrollTop =
document.documentElement.scrollHeight -
document.documentElement.clientHeight
const to = clamp(minScrollTop, values.y.goal + value, maxScrollTop)
values.y.start({ to })
}
React.useEffect(() => {
function handleWheel() {
if (values.x.is('ACTIVE') || values.y.is('ACTIVE')) {
values.x.stop()
values.y.stop()
}
values.x.set(window.scrollX)
values.y.set(window.scrollY)
}
function handlePointerDown(event: PointerEvent) {
if (event.pointerType === 'mouse') {
isMouseAction.current = true
}
}
function handlePointerUp() {
isMouseAction.current = false
}
window.addEventListener('wheel', handleWheel)
window.addEventListener('pointerdown', handlePointerDown)
window.addEventListener('pointerup', handlePointerUp)
return function teardown() {
window.removeEventListener('wheel', handleWheel)
window.removeEventListener('pointerdown', handlePointerDown)
window.removeEventListener('pointerup', handlePointerUp)
}
}, [values])
useDrag(
({ delta: [x, y] }) => {
if (isMouseAction.current) {
setX(-x)
setY(-y)
}
},
{
domTarget: isServer ? undefined : document.documentElement,
},
)
}
export { useDragScroll }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment