|
1 | | -import { useState, useEffect, useCallback, useRef } from 'react'; |
2 | | -import { |
3 | | - Axis, |
4 | | - Direction, |
5 | | - ScrollInfo, |
6 | | - ScrollPosition, |
7 | | - ScrollProps |
8 | | -} from './types'; |
| 1 | +import useDetectScroll from './useDetectScroll'; |
9 | 2 |
|
10 | | -/** |
11 | | - * useDetectScroll hook. |
12 | | - * |
13 | | - * This hook provides a mechanism to detect the scroll direction and position. |
14 | | - * It will return the scroll direction as a string (up, down, left, right, or still) based on user scrolling, |
15 | | - * as well as the scroll position from the top, bottom, left, and right edges of the page. |
16 | | - * |
17 | | - * @example |
18 | | - * |
19 | | - * import useDetectScroll, { Axis, Direction } from '@smakss/react-scroll-direction'; |
20 | | - * |
21 | | - * function App() { |
22 | | - * const customElementRef = useRef<HTMLDivElement>(null); |
23 | | - * const [customElement, setCustomElement] = useState<HTMLDivElement>(); |
24 | | - * |
25 | | - * const { scrollDir, scrollPosition } = useDetectScroll({ |
26 | | - * target: customElement, |
27 | | - * thr: 100, |
28 | | - * axis: Axis.Y, |
29 | | - * scrollUp: Direction.Up, |
30 | | - * scrollDown: Direction.Down, |
31 | | - * still: Direction.Still |
32 | | - * }); |
33 | | - * |
34 | | - * useEffect(() => { |
35 | | - * if (customElementRef.current) { |
36 | | - * setCustomElement(customElementRef.current); |
37 | | - * } |
38 | | - * }, [customElementRef]); |
39 | | - * |
40 | | - * return ( |
41 | | - * <div> |
42 | | - * <p>Current scroll direction: {scrollDir}</p> |
43 | | - * <p>Scroll position - Top: {scrollPosition.top}, Bottom: {scrollPosition.bottom}, |
44 | | - * Left: {scrollPosition.left}, Right: {scrollPosition.right}</p> |
45 | | - * </div> |
46 | | - * ); |
47 | | - * } |
48 | | - * |
49 | | - * @param {ScrollProps} props - The properties related to scrolling. |
50 | | - * @returns {ScrollInfo} - The current direction and position of scrolling. |
51 | | - */ |
52 | | -function useDetectScroll(props: ScrollProps = {}): ScrollInfo { |
53 | | - const { |
54 | | - target = typeof window !== 'undefined' ? window : undefined, |
55 | | - thr = 0, |
56 | | - axis = Axis.Y, |
57 | | - scrollUp = axis === Axis.Y ? Direction.Up : Direction.Left, |
58 | | - scrollDown = axis === Axis.Y ? Direction.Down : Direction.Right, |
59 | | - still = Direction.Still |
60 | | - } = props; |
61 | | - |
62 | | - const [scrollDir, setScrollDir] = useState<Direction>(still); |
63 | | - const [scrollPosition, setScrollPosition] = useState<ScrollPosition>({ |
64 | | - top: 0, |
65 | | - bottom: 0, |
66 | | - left: 0, |
67 | | - right: 0 |
68 | | - }); |
69 | | - |
70 | | - const threshold = Math.max(0, thr); |
71 | | - const ticking = useRef(false); |
72 | | - const lastScroll = useRef(0); |
73 | | - |
74 | | - /** Function to update scroll direction */ |
75 | | - const updateScrollDir = useCallback(() => { |
76 | | - if (!target) return; |
77 | | - |
78 | | - let scroll: number; |
79 | | - if (target instanceof Window) { |
80 | | - scroll = axis === Axis.Y ? target.scrollY : target.scrollX; |
81 | | - } else { |
82 | | - scroll = axis === Axis.Y ? target.scrollTop : target.scrollLeft; |
83 | | - } |
84 | | - |
85 | | - if (Math.abs(scroll - lastScroll.current) >= threshold) { |
86 | | - setScrollDir(scroll > lastScroll.current ? scrollDown : scrollUp); |
87 | | - lastScroll.current = Math.max(0, scroll); |
88 | | - } |
89 | | - ticking.current = false; |
90 | | - }, [target, axis, threshold, scrollDown, scrollUp]); |
91 | | - |
92 | | - useEffect(() => { |
93 | | - if (!target) { |
94 | | - console.warn( |
95 | | - 'useDetectScroll: target is not set. Falling back to window.' |
96 | | - ); |
97 | | - return; |
98 | | - } |
99 | | - |
100 | | - /** Function to update scroll position */ |
101 | | - const updateScrollPosition = () => { |
102 | | - if (!target) return; |
103 | | - |
104 | | - const top = target instanceof Window ? target.scrollY : target.scrollTop; |
105 | | - const left = |
106 | | - target instanceof Window ? target.scrollX : target.scrollLeft; |
107 | | - |
108 | | - const bottom = |
109 | | - (target instanceof Window |
110 | | - ? document.documentElement.scrollHeight - target.innerHeight |
111 | | - : target.scrollHeight - target.clientHeight) - top; |
112 | | - const right = |
113 | | - (target instanceof Window |
114 | | - ? document.documentElement.scrollWidth - target.innerWidth |
115 | | - : target.scrollWidth - target.clientWidth) - left; |
116 | | - |
117 | | - setScrollPosition({ top, bottom, left, right }); |
118 | | - }; |
119 | | - |
120 | | - updateScrollPosition(); |
121 | | - |
122 | | - const targetElement = target as EventTarget; |
123 | | - targetElement.addEventListener('scroll', updateScrollPosition); |
124 | | - |
125 | | - return () => { |
126 | | - targetElement.removeEventListener('scroll', updateScrollPosition); |
127 | | - }; |
128 | | - }, [target]); |
129 | | - |
130 | | - useEffect(() => { |
131 | | - if (!target) { |
132 | | - console.warn( |
133 | | - 'useDetectScroll: target is not set. Falling back to window.' |
134 | | - ); |
135 | | - return; |
136 | | - } |
137 | | - |
138 | | - if (target instanceof Window) { |
139 | | - lastScroll.current = axis === Axis.Y ? target.scrollY : target.scrollX; |
140 | | - } else { |
141 | | - lastScroll.current = |
142 | | - axis === Axis.Y ? target.scrollTop : target.scrollLeft; |
143 | | - } |
144 | | - |
145 | | - const onScroll = () => { |
146 | | - if (!ticking.current) { |
147 | | - window.requestAnimationFrame(updateScrollDir); |
148 | | - ticking.current = true; |
149 | | - } |
150 | | - }; |
151 | | - |
152 | | - const targetElement = target as EventTarget; |
153 | | - targetElement.addEventListener('scroll', onScroll); |
154 | | - |
155 | | - return () => targetElement.removeEventListener('scroll', onScroll); |
156 | | - }, [target, axis, updateScrollDir]); |
157 | | - |
158 | | - return { scrollDir, scrollPosition }; |
159 | | -} |
160 | | - |
161 | | -export { Axis, Direction }; |
162 | 3 | export default useDetectScroll; |
| 4 | +export { Axis, Direction } from './types'; |
0 commit comments