this repo has no description
at main 153 lines 4.5 kB view raw
1import { useEffect, useLayoutEffect, useRef, useState } from 'preact/hooks'; 2import { useThrottledCallback } from 'use-debounce'; 3 4export default function useScrollFn( 5 { 6 scrollableRef, 7 distanceFromStart = 1, // ratio of clientHeight/clientWidth 8 distanceFromEnd = 1, // ratio of clientHeight/clientWidth 9 scrollThresholdStart = 10, 10 scrollThresholdEnd = 10, 11 direction = 'vertical', 12 distanceFromStartPx: _distanceFromStartPx, 13 distanceFromEndPx: _distanceFromEndPx, 14 init, 15 } = {}, 16 callback, 17 deps, 18) { 19 if (!callback) return; 20 // const [scrollDirection, setScrollDirection] = useState(null); 21 // const [reachStart, setReachStart] = useState(false); 22 // const [reachEnd, setReachEnd] = useState(false); 23 // const [nearReachStart, setNearReachStart] = useState(false); 24 // const [nearReachEnd, setNearReachEnd] = useState(false); 25 const isVertical = direction === 'vertical'; 26 const previousScrollStart = useRef(null); 27 const scrollDirection = useRef(null); 28 29 const onScroll = useThrottledCallback(() => { 30 // let scrollDirection = null; 31 let reachStart = false; 32 let reachEnd = false; 33 let nearReachStart = false; 34 let nearReachEnd = false; 35 36 const scrollableElement = scrollableRef.current; 37 const { 38 scrollTop, 39 scrollLeft, 40 scrollHeight, 41 scrollWidth, 42 clientHeight, 43 clientWidth, 44 } = scrollableElement; 45 const scrollStart = isVertical ? scrollTop : scrollLeft; 46 const scrollDimension = isVertical ? scrollHeight : scrollWidth; 47 const clientDimension = isVertical ? clientHeight : clientWidth; 48 const scrollDistance = Math.abs(scrollStart - previousScrollStart.current); 49 const distanceFromStartPx = 50 _distanceFromStartPx || 51 Math.min( 52 clientDimension * distanceFromStart, 53 scrollDimension, 54 scrollStart, 55 ); 56 const distanceFromEndPx = 57 _distanceFromEndPx || 58 Math.min( 59 clientDimension * distanceFromEnd, 60 scrollDimension, 61 scrollDimension - scrollStart - clientDimension, 62 ); 63 64 if ( 65 scrollDistance >= 66 (previousScrollStart.current < scrollStart 67 ? scrollThresholdEnd 68 : scrollThresholdStart) 69 ) { 70 // setScrollDirection( 71 // previousScrollStart.current < scrollStart ? 'end' : 'start', 72 // ); 73 scrollDirection.current = 74 previousScrollStart.current < scrollStart ? 'end' : 'start'; 75 previousScrollStart.current = scrollStart; 76 } 77 78 // setReachStart(scrollStart <= 0); 79 // setReachEnd(scrollStart + clientDimension >= scrollDimension); 80 // setNearReachStart(scrollStart <= distanceFromStartPx); 81 // setNearReachEnd( 82 // scrollStart + clientDimension >= scrollDimension - distanceFromEndPx, 83 // ); 84 reachStart = scrollStart <= 0; 85 reachEnd = scrollStart + clientDimension >= scrollDimension; 86 nearReachStart = scrollStart <= distanceFromStartPx; 87 nearReachEnd = 88 scrollStart + clientDimension >= scrollDimension - distanceFromEndPx; 89 90 callback({ 91 scrollDirection: scrollDirection.current, 92 reachStart, 93 reachEnd, 94 nearReachStart, 95 nearReachEnd, 96 }); 97 }, 500); 98 99 useLayoutEffect(() => { 100 const scrollableElement = scrollableRef.current; 101 if (!scrollableElement) return {}; 102 previousScrollStart.current = 103 scrollableElement[isVertical ? 'scrollTop' : 'scrollLeft']; 104 105 scrollableElement.addEventListener('scroll', onScroll, { passive: true }); 106 107 return () => scrollableElement.removeEventListener('scroll', onScroll); 108 }, [ 109 distanceFromStart, 110 distanceFromEnd, 111 scrollThresholdStart, 112 scrollThresholdEnd, 113 ...deps, 114 ]); 115 116 // useEffect(() => { 117 // callback({ 118 // scrollDirection, 119 // reachStart, 120 // reachEnd, 121 // nearReachStart, 122 // nearReachEnd, 123 // }); 124 // }, [ 125 // scrollDirection, 126 // reachStart, 127 // reachEnd, 128 // nearReachStart, 129 // nearReachEnd, 130 // ...deps, 131 // ]); 132 133 useEffect(() => { 134 if (init && scrollableRef.current) { 135 queueMicrotask(() => { 136 scrollableRef.current.dispatchEvent(new Event('scroll')); 137 }); 138 } 139 }, [init]); 140 141 // return { 142 // scrollDirection, 143 // reachStart, 144 // reachEnd, 145 // nearReachStart, 146 // nearReachEnd, 147 // init: () => { 148 // if (scrollableRef.current) { 149 // scrollableRef.current.dispatchEvent(new Event('scroll')); 150 // } 151 // }, 152 // }; 153}