1
1
import { useState , useEffect , useCallback , useRef } from 'react' ;
2
-
3
- /** Enumeration for axis values */
4
- export enum Axis {
5
- /**
6
- * The x-axis represents the horizontal direction.
7
- */
8
- X = 'x' ,
9
- /**
10
- * The y-axis represents the vertical direction.
11
- */
12
- Y = 'y'
13
- }
14
-
15
- /** Enumeration for direction values */
16
- export enum Direction {
17
- /**
18
- * The up direction represents the scroll direction moving towards the top.
19
- */
20
- Up = 'up' ,
21
- /**
22
- * The down direction represents the scroll direction moving towards the bottom.
23
- */
24
- Down = 'down' ,
25
- /**
26
- * The left direction represents the scroll direction moving towards the left.
27
- */
28
- Left = 'left' ,
29
- /**
30
- * The right direction represents the scroll direction moving towards the right.
31
- */
32
- Right = 'right' ,
33
- /**
34
- * The still direction represents the scroll direction when the user is not scrolling.
35
- */
36
- Still = 'still'
37
- }
38
-
39
- type ScrollPosition = {
40
- /**
41
- * The top position represents the distance from the top edge of the page.
42
- */
43
- top : number ;
44
- /**
45
- * The bottom position represents the distance from the bottom edge of the page.
46
- */
47
- bottom : number ;
48
- /**
49
- * The left position represents the distance from the left edge of the page.
50
- */
51
- left : number ;
52
- /**
53
- * The right position represents the distance from the right edge of the page.
54
- */
55
- right : number ;
56
- } ;
57
-
58
- /** Type declaration for the returned scroll information */
59
- type ScrollInfo = {
60
- /**
61
- * The scrollDir represents the current scroll direction.
62
- */
63
- scrollDir : Direction ;
64
- /**
65
- * The scrollPosition represents the current scroll position.
66
- */
67
- scrollPosition : ScrollPosition ;
68
- } ;
69
-
70
- /** Type declaration for scroll properties */
71
- type ScrollProps = {
72
- /**
73
- * The target represents the scrollable element to check for scroll detection.
74
- */
75
- target ?: HTMLDivElement | Window ;
76
- /**
77
- * The thr represents the threshold value for scroll detection.
78
- */
79
- thr ?: number ;
80
- /**
81
- * The axis represents the scroll axis (x or y).
82
- */
83
- axis ?: Axis ;
84
- /**
85
- * The scrollUp represents the scroll direction when moving up.
86
- */
87
- scrollUp ?: Direction ;
88
- /**
89
- * The scrollDown represents the scroll direction when moving down.
90
- */
91
- scrollDown ?: Direction ;
92
- /**
93
- * The still represents the scroll direction when the user is not scrolling.
94
- */
95
- still ?: Direction ;
96
- } ;
2
+ import {
3
+ Axis ,
4
+ Direction ,
5
+ ScrollInfo ,
6
+ ScrollPosition ,
7
+ ScrollProps
8
+ } from './types' ;
97
9
98
10
/**
99
11
* useDetectScroll hook.
@@ -107,14 +19,24 @@ type ScrollProps = {
107
19
* import useDetectScroll, { Axis, Direction } from '@smakss/react-scroll-direction';
108
20
*
109
21
* function App() {
22
+ * const customElementRef = useRef<HTMLDivElement>(null);
23
+ * const [customElement, setCustomElement] = useState<HTMLDivElement>();
24
+ *
110
25
* const { scrollDir, scrollPosition } = useDetectScroll({
26
+ * target: customElement,
111
27
* thr: 100,
112
28
* axis: Axis.Y,
113
29
* scrollUp: Direction.Up,
114
30
* scrollDown: Direction.Down,
115
31
* still: Direction.Still
116
32
* });
117
33
*
34
+ * useEffect(() => {
35
+ * if (customElementRef.current) {
36
+ * setCustomElement(customElementRef.current);
37
+ * }
38
+ * }, [customElementRef]);
39
+ *
118
40
* return (
119
41
* <div>
120
42
* <p>Current scroll direction: {scrollDir}</p>
@@ -129,7 +51,7 @@ type ScrollProps = {
129
51
*/
130
52
function useDetectScroll ( props : ScrollProps = { } ) : ScrollInfo {
131
53
const {
132
- target = window ,
54
+ target = typeof window !== 'undefined' ? window : undefined ,
133
55
thr = 0 ,
134
56
axis = Axis . Y ,
135
57
scrollUp = axis === Axis . Y ? Direction . Up : Direction . Left ,
@@ -151,14 +73,13 @@ function useDetectScroll(props: ScrollProps = {}): ScrollInfo {
151
73
152
74
/** Function to update scroll direction */
153
75
const updateScrollDir = useCallback ( ( ) => {
76
+ if ( ! target ) return ;
77
+
154
78
let scroll : number ;
155
79
if ( target instanceof Window ) {
156
80
scroll = axis === Axis . Y ? target . scrollY : target . scrollX ;
157
81
} else {
158
- scroll =
159
- axis === Axis . Y
160
- ? ( target as HTMLDivElement ) . scrollTop
161
- : ( target as HTMLDivElement ) . scrollLeft ;
82
+ scroll = axis === Axis . Y ? target . scrollTop : target . scrollLeft ;
162
83
}
163
84
164
85
if ( Math . abs ( scroll - lastScroll . current ) >= threshold ) {
@@ -169,33 +90,33 @@ function useDetectScroll(props: ScrollProps = {}): ScrollInfo {
169
90
} , [ target , axis , threshold , scrollDown , scrollUp ] ) ;
170
91
171
92
useEffect ( ( ) => {
93
+ if ( ! target ) {
94
+ console . warn (
95
+ 'useDetectScroll: target is not set. Falling back to window.'
96
+ ) ;
97
+ return ;
98
+ }
99
+
172
100
/** Function to update scroll position */
173
101
const updateScrollPosition = ( ) => {
174
- const top =
175
- target instanceof Window
176
- ? target . scrollY
177
- : ( target as HTMLDivElement ) . scrollTop ;
102
+ if ( ! target ) return ;
103
+
104
+ const top = target instanceof Window ? target . scrollY : target . scrollTop ;
178
105
const left =
179
- target instanceof Window
180
- ? target . scrollX
181
- : ( target as HTMLDivElement ) . scrollLeft ;
106
+ target instanceof Window ? target . scrollX : target . scrollLeft ;
107
+
182
108
const bottom =
183
- document . documentElement . scrollHeight -
184
109
( target instanceof Window
185
- ? target . innerHeight
186
- : ( target as HTMLDivElement ) . scrollHeight ) -
187
- top ;
110
+ ? document . documentElement . scrollHeight - target . innerHeight
111
+ : target . scrollHeight - target . clientHeight ) - top ;
188
112
const right =
189
- document . documentElement . scrollWidth -
190
113
( target instanceof Window
191
- ? target . innerWidth
192
- : ( target as HTMLDivElement ) . scrollWidth ) -
193
- left ;
114
+ ? document . documentElement . scrollWidth - target . innerWidth
115
+ : target . scrollWidth - target . clientWidth ) - left ;
194
116
195
117
setScrollPosition ( { top, bottom, left, right } ) ;
196
118
} ;
197
119
198
- /** Call the update function when the component mounts */
199
120
updateScrollPosition ( ) ;
200
121
201
122
const targetElement = target as EventTarget ;
@@ -207,16 +128,20 @@ function useDetectScroll(props: ScrollProps = {}): ScrollInfo {
207
128
} , [ target ] ) ;
208
129
209
130
useEffect ( ( ) => {
131
+ if ( ! target ) {
132
+ console . warn (
133
+ 'useDetectScroll: target is not set. Falling back to window.'
134
+ ) ;
135
+ return ;
136
+ }
137
+
210
138
if ( target instanceof Window ) {
211
139
lastScroll . current = axis === Axis . Y ? target . scrollY : target . scrollX ;
212
140
} else {
213
141
lastScroll . current =
214
- axis === Axis . Y
215
- ? ( target as HTMLDivElement ) . scrollTop
216
- : ( target as HTMLDivElement ) . scrollLeft ;
142
+ axis === Axis . Y ? target . scrollTop : target . scrollLeft ;
217
143
}
218
144
219
- /** Function to handle onScroll event */
220
145
const onScroll = ( ) => {
221
146
if ( ! ticking . current ) {
222
147
window . requestAnimationFrame ( updateScrollDir ) ;
@@ -233,4 +158,5 @@ function useDetectScroll(props: ScrollProps = {}): ScrollInfo {
233
158
return { scrollDir, scrollPosition } ;
234
159
}
235
160
161
+ export { Axis , Direction } ;
236
162
export default useDetectScroll ;
0 commit comments