UNPKG

smooth-auto-scroll

Version:

Smooth auto-scroll React hook and component for ultra-smooth motion at any speed.

1 lines 20.8 kB
{"version":3,"sources":["../src/useSmoothAutoScroll.ts","../src/AutoScrollContainer.tsx"],"sourcesContent":["import { useEffect, useRef, useCallback } from \"react\";\n\nexport type SmoothAutoScrollOptions = {\n enabled?: boolean;\n containerRef: React.RefObject<HTMLElement>;\n innerRef: React.RefObject<HTMLElement>;\n pxPerSecond: number;\n bottomTolerance?: number;\n topTolerance?: number;\n capDtMs?: number;\n pauseEvents?: Array<keyof GlobalEventHandlersEventMap>;\n resumeEvents?: Array<keyof GlobalEventHandlersEventMap>;\n smoothingFactor?: number;\n accelerationTime?: number;\n direction?: \"down\" | \"up\";\n resumeDelay?: number;\n pauseOnHover?: boolean;\n pauseOnFocus?: boolean;\n startOffset?: number;\n endOffset?: number;\n respectReducedMotion?: boolean;\n // Callbacks\n onStart?: () => void;\n onPause?: () => void;\n onResume?: () => void;\n onReachEnd?: () => void;\n onReachTop?: () => void;\n};\n\nexport function useSmoothAutoScroll({\n enabled = true,\n containerRef,\n innerRef,\n pxPerSecond,\n bottomTolerance = 1,\n topTolerance = 1,\n capDtMs = 16.67, // ~60fps for smoother updates\n pauseEvents = [\"wheel\", \"touchmove\", \"keydown\", \"mousedown\", \"focus\"],\n resumeEvents = [\"mouseleave\", \"touchend\", \"touchcancel\"],\n smoothingFactor = 0.1, // For smooth velocity changes\n accelerationTime = 1000, // 1 second to reach full speed\n direction = \"down\",\n resumeDelay = 0,\n pauseOnHover = false,\n pauseOnFocus = false,\n startOffset = 0,\n endOffset = 0,\n respectReducedMotion = true,\n // Callbacks\n onStart,\n onPause,\n onResume,\n onReachEnd,\n onReachTop,\n}: SmoothAutoScrollOptions) {\n const rafIdRef = useRef<number | null>(null);\n const lastTsRef = useRef<number | null>(null);\n const accumRef = useRef(0);\n const pausedRef = useRef(false);\n const startTimeRef = useRef<number | null>(null);\n const currentVelocityRef = useRef(0);\n const targetVelocityRef = useRef(pxPerSecond);\n const currentDirectionRef = useRef<\"down\" | \"up\">(direction);\n const hasStartedRef = useRef(false);\n const resumeTimeoutRef = useRef<number | null>(null);\n const reducedMotionRef = useRef(false);\n\n const resetVisualShift = useCallback(() => {\n const inner = innerRef.current;\n if (inner) inner.style.transform = \"\";\n }, [innerRef]);\n\n // Check for reduced motion preference\n useEffect(() => {\n if (respectReducedMotion && typeof window !== \"undefined\") {\n const mediaQuery = window.matchMedia(\"(prefers-reduced-motion: reduce)\");\n reducedMotionRef.current = mediaQuery.matches;\n\n const handleChange = (e: MediaQueryListEvent) => {\n reducedMotionRef.current = e.matches;\n };\n\n mediaQuery.addEventListener(\"change\", handleChange);\n return () => mediaQuery.removeEventListener(\"change\", handleChange);\n }\n }, [respectReducedMotion]);\n\n useEffect(() => {\n if (!enabled) return;\n\n lastTsRef.current = null;\n accumRef.current = 0;\n pausedRef.current = false;\n startTimeRef.current = null;\n currentVelocityRef.current = 0;\n targetVelocityRef.current = pxPerSecond;\n currentDirectionRef.current = direction;\n hasStartedRef.current = false;\n resetVisualShift();\n\n // Clear any pending resume timeout\n if (resumeTimeoutRef.current) {\n clearTimeout(resumeTimeoutRef.current);\n resumeTimeoutRef.current = null;\n }\n\n const step = (ts: number) => {\n const el = containerRef.current;\n const inner = innerRef.current;\n if (!el || !inner) {\n rafIdRef.current = requestAnimationFrame(step);\n return;\n }\n\n if (lastTsRef.current == null) {\n lastTsRef.current = ts;\n startTimeRef.current = ts;\n }\n\n const dt = Math.min(ts - (lastTsRef.current ?? ts), capDtMs);\n lastTsRef.current = ts;\n\n // Skip animation if reduced motion is preferred\n if (respectReducedMotion && reducedMotionRef.current) {\n rafIdRef.current = requestAnimationFrame(step);\n return;\n }\n\n const currentDirection = currentDirectionRef.current;\n const isScrollingDown = currentDirection === \"down\";\n\n if (!pausedRef.current) {\n // Call onStart callback on first movement\n if (!hasStartedRef.current) {\n hasStartedRef.current = true;\n onStart?.();\n }\n\n // Smooth acceleration from 0 to target velocity\n const baseVelocity = pxPerSecond;\n let targetVelocity: number;\n\n if (accelerationTime <= 0) {\n // Instant full speed when accelerationTime is 0\n targetVelocity = baseVelocity * (isScrollingDown ? 1 : -1);\n } else {\n const elapsedTime = ts - (startTimeRef.current ?? ts);\n const accelerationProgress = Math.min(\n elapsedTime / accelerationTime,\n 1\n );\n const easedProgress = 1 - Math.pow(1 - accelerationProgress, 3); // Cubic ease-out\n targetVelocity =\n baseVelocity * easedProgress * (isScrollingDown ? 1 : -1);\n }\n\n // Smooth velocity interpolation for responsive changes\n currentVelocityRef.current +=\n (targetVelocity - currentVelocityRef.current) * smoothingFactor;\n\n // Calculate smooth movement with fractional pixels\n const deltaPixels = (currentVelocityRef.current * dt) / 1000;\n accumRef.current += deltaPixels;\n\n const intDelta = Math.floor(Math.abs(accumRef.current));\n const frac = Math.abs(accumRef.current) - intDelta;\n\n if (intDelta > 0) {\n if (isScrollingDown) {\n el.scrollTop += intDelta;\n } else {\n el.scrollTop -= intDelta;\n }\n accumRef.current = accumRef.current >= 0 ? frac : -frac;\n }\n\n // Apply smooth visual offset for ultra-smooth motion\n const fracOffset = isScrollingDown ? -frac : frac;\n inner.style.transform = `translate3d(0, ${fracOffset}px, 0)`;\n\n // Check boundaries\n const scrollTop = el.scrollTop;\n const scrollHeight = el.scrollHeight;\n const clientHeight = el.clientHeight;\n\n const atBottom =\n scrollTop + clientHeight >=\n scrollHeight - bottomTolerance - endOffset;\n const atTop = scrollTop <= topTolerance + startOffset;\n\n if (isScrollingDown && atBottom) {\n onReachEnd?.();\n resetVisualShift();\n } else if (!isScrollingDown && atTop) {\n onReachTop?.();\n resetVisualShift();\n }\n }\n\n rafIdRef.current = requestAnimationFrame(step);\n };\n\n rafIdRef.current = requestAnimationFrame(step);\n return () => {\n if (rafIdRef.current != null) cancelAnimationFrame(rafIdRef.current);\n resetVisualShift();\n };\n }, [\n enabled,\n containerRef,\n innerRef,\n pxPerSecond,\n bottomTolerance,\n topTolerance,\n capDtMs,\n smoothingFactor,\n accelerationTime,\n direction,\n startOffset,\n endOffset,\n respectReducedMotion,\n onStart,\n onReachEnd,\n onReachTop,\n resetVisualShift,\n ]);\n\n // Update target velocity when pxPerSecond changes without restarting the entire animation\n useEffect(() => {\n targetVelocityRef.current = pxPerSecond;\n }, [pxPerSecond]);\n\n useEffect(() => {\n const el = containerRef.current;\n if (!el) return;\n\n const onUser = (_event: Event) => {\n if (!pausedRef.current) {\n onPause?.();\n }\n pausedRef.current = true;\n resetVisualShift();\n accumRef.current = 0;\n currentVelocityRef.current = 0;\n\n // Clear any pending resume timeout\n if (resumeTimeoutRef.current) {\n clearTimeout(resumeTimeoutRef.current);\n resumeTimeoutRef.current = null;\n }\n };\n\n const onScroll = () => {\n // User scroll events can be handled here if needed in the future\n };\n\n const onResumeEvent = (_event: Event) => {\n if (resumeDelay > 0) {\n resumeTimeoutRef.current = setTimeout(() => {\n if (pausedRef.current) {\n onResume?.();\n }\n pausedRef.current = false;\n lastTsRef.current = null;\n startTimeRef.current = null;\n }, resumeDelay);\n } else {\n if (pausedRef.current) {\n onResume?.();\n }\n pausedRef.current = false;\n lastTsRef.current = null;\n startTimeRef.current = null;\n }\n };\n\n const onHover = (event: Event) => {\n if (pauseOnHover) {\n onUser(event);\n }\n };\n\n const onFocus = (event: Event) => {\n if (pauseOnFocus) {\n onUser(event);\n }\n };\n\n for (const evt of pauseEvents) {\n el.addEventListener(evt, onUser, { passive: true });\n }\n for (const evt of resumeEvents) {\n el.addEventListener(evt, onResumeEvent, { passive: true });\n }\n el.addEventListener(\"scroll\", onScroll, { passive: true });\n\n if (pauseOnHover) {\n el.addEventListener(\"mouseenter\", onHover);\n }\n\n if (pauseOnFocus) {\n el.addEventListener(\"focus\", onFocus, { passive: true });\n }\n\n const onVis = () => {\n if (document.hidden) {\n pausedRef.current = true;\n } else {\n pausedRef.current = false;\n lastTsRef.current = null;\n startTimeRef.current = null;\n }\n };\n document.addEventListener(\"visibilitychange\", onVis);\n\n return () => {\n for (const evt of pauseEvents) {\n el.removeEventListener(evt, onUser);\n }\n for (const evt of resumeEvents) {\n el.removeEventListener(evt, onResumeEvent);\n }\n el.removeEventListener(\"scroll\", onScroll);\n\n if (pauseOnHover) {\n el.removeEventListener(\"mouseenter\", onHover);\n }\n\n if (pauseOnFocus) {\n el.removeEventListener(\"focus\", onFocus);\n }\n\n document.removeEventListener(\"visibilitychange\", onVis);\n\n // Clear any pending timeouts\n if (resumeTimeoutRef.current) {\n clearTimeout(resumeTimeoutRef.current);\n }\n };\n }, [\n containerRef,\n pauseEvents,\n resumeEvents,\n bottomTolerance,\n topTolerance,\n endOffset,\n startOffset,\n resumeDelay,\n pauseOnHover,\n pauseOnFocus,\n onPause,\n onResume,\n resetVisualShift,\n ]);\n\n return {\n pause: () => {\n if (!pausedRef.current) {\n onPause?.();\n }\n pausedRef.current = true;\n resetVisualShift();\n },\n resume: () => {\n if (pausedRef.current) {\n onResume?.();\n }\n pausedRef.current = false;\n lastTsRef.current = null;\n startTimeRef.current = null;\n },\n reset: () => {\n accumRef.current = 0;\n hasStartedRef.current = false;\n currentDirectionRef.current = direction;\n resetVisualShift();\n },\n get paused() {\n return pausedRef.current;\n },\n get currentDirection() {\n return currentDirectionRef.current;\n },\n get hasStarted() {\n return hasStartedRef.current;\n },\n };\n}\n","import React, { useEffect, useRef } from \"react\";\nimport { useSmoothAutoScroll } from \"./useSmoothAutoScroll\";\n\nexport type AutoScrollContainerProps = {\n containerRef?: React.RefObject<HTMLElement>;\n enabled?: boolean;\n pxPerSecond: number;\n bottomTolerance?: number;\n topTolerance?: number;\n capDtMs?: number;\n smoothingFactor?: number;\n accelerationTime?: number;\n pauseEvents?: Array<keyof GlobalEventHandlersEventMap>;\n resumeEvents?: Array<keyof GlobalEventHandlersEventMap>;\n direction?: \"down\" | \"up\";\n resumeDelay?: number;\n pauseOnHover?: boolean;\n pauseOnFocus?: boolean;\n startOffset?: number;\n endOffset?: number;\n respectReducedMotion?: boolean;\n // Callbacks\n onStart?: () => void;\n onPause?: () => void;\n onResume?: () => void;\n onReachEnd?: () => void;\n onReachTop?: () => void;\n\n className?: string;\n style?: React.CSSProperties;\n children: React.ReactNode;\n} & React.HTMLAttributes<HTMLDivElement>;\n\nexport const AutoScrollContainer: React.FC<AutoScrollContainerProps> = ({\n containerRef,\n enabled = true,\n pxPerSecond,\n bottomTolerance,\n topTolerance,\n capDtMs,\n smoothingFactor,\n accelerationTime,\n pauseEvents,\n resumeEvents,\n direction,\n resumeDelay,\n pauseOnHover,\n pauseOnFocus,\n startOffset,\n endOffset,\n respectReducedMotion,\n // Callbacks\n onStart,\n onPause,\n onResume,\n onReachEnd,\n onReachTop,\n className,\n style,\n children,\n ...restProps\n}) => {\n const outerRef = useRef<HTMLDivElement>(null);\n const innerRef = useRef<HTMLDivElement>(null);\n const scrollOwnerRef =\n containerRef ?? (outerRef as React.RefObject<HTMLElement>);\n\n useSmoothAutoScroll({\n enabled,\n containerRef: scrollOwnerRef,\n innerRef: innerRef as React.RefObject<HTMLElement>,\n pxPerSecond,\n bottomTolerance,\n topTolerance,\n capDtMs,\n smoothingFactor,\n accelerationTime,\n pauseEvents,\n resumeEvents,\n direction,\n resumeDelay,\n pauseOnHover,\n pauseOnFocus,\n startOffset,\n endOffset,\n respectReducedMotion,\n // Callbacks\n onStart,\n onPause,\n onResume,\n onReachEnd,\n onReachTop,\n });\n\n useEffect(() => {\n if (!containerRef && outerRef.current) {\n outerRef.current.style.overflowY = \"auto\";\n outerRef.current.style.willChange = \"transform\";\n }\n\n // Set up smooth animation styles\n if (innerRef.current) {\n innerRef.current.style.willChange = \"transform\";\n innerRef.current.style.backfaceVisibility = \"hidden\";\n innerRef.current.style.perspective = \"1000px\";\n }\n }, [containerRef]);\n\n return (\n <div ref={outerRef} className={className} style={style} {...restProps}>\n <div ref={innerRef}>{children}</div>\n </div>\n );\n};\n"],"mappings":"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","names":["useEffect","useRef","useRef","useEffect"]}