this repo has no description
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}