1
- import { useEffect , useRef } from 'react'
1
+ import { useEffect , useRef , useState } from 'react'
2
2
import { isNullOrUndefined } from '@Shared/Helpers'
3
3
import { noop } from '@Common/Helper'
4
- import { UseStickyEventProps } from './types'
5
- import { FALLBACK_SENTINEL_HEIGHT , OBSERVER_ROOT_MARGIN , OBSERVER_THRESHOLD } from './constants'
4
+ import { UseStickyEventProps , UseStickyEventReturnType } from './types'
5
+ import { OBSERVER_ROOT_MARGIN , OBSERVER_THRESHOLD } from './constants'
6
+ import { getHeightForStickyElementTopOffset } from './utils'
6
7
7
8
import './styles.scss'
8
9
@@ -12,14 +13,13 @@ import './styles.scss'
12
13
* as a reference for the implementation
13
14
*/
14
15
const useStickyEvent = < T extends HTMLElement = HTMLDivElement > ( {
15
- callback,
16
16
containerSelector,
17
17
containerRef,
18
18
identifier,
19
- topOffset,
20
19
isStickyElementMounted = true ,
21
- } : UseStickyEventProps < T > ) => {
20
+ } : UseStickyEventProps < T > ) : UseStickyEventReturnType < T > => {
22
21
const stickyElementRef = useRef < T > ( null )
22
+ const [ isStuck , setIsStuck ] = useState ( false )
23
23
24
24
useEffect (
25
25
( ) => {
@@ -43,7 +43,6 @@ const useStickyEvent = <T extends HTMLElement = HTMLDivElement>({
43
43
// Using IntersectionObserver, we observe both the sticky element and the sentinel.
44
44
// When the sentinel is not fully in view, isIntersecting is false,
45
45
// indicating the sticky element is stuck given it is fully in view.
46
- let previousStuckState : boolean
47
46
let hasSentinelLeftView : boolean
48
47
let hasHeaderLeftView : boolean
49
48
@@ -65,12 +64,7 @@ const useStickyEvent = <T extends HTMLElement = HTMLDivElement>({
65
64
}
66
65
} )
67
66
68
- const isStuck = hasSentinelLeftView && ! hasHeaderLeftView
69
-
70
- if ( isNullOrUndefined ( previousStuckState ) || isStuck !== previousStuckState ) {
71
- callback ( isStuck )
72
- previousStuckState = isStuck
73
- }
67
+ setIsStuck ( hasSentinelLeftView && ! hasHeaderLeftView )
74
68
} ,
75
69
{ root : stickyElementParent , threshold : OBSERVER_THRESHOLD , rootMargin : OBSERVER_ROOT_MARGIN } ,
76
70
)
@@ -86,15 +80,7 @@ const useStickyEvent = <T extends HTMLElement = HTMLDivElement>({
86
80
// The sentinel element's height must exceed the sticky element's top CSS value.
87
81
// This guarantees that when the sticky element sticks to the container's edge,
88
82
// the sentinel element will extend beyond the scroll container.
89
- sentinelElement . style . height = topOffset
90
- ? `calc(${ topOffset } + 1px)`
91
- : ( window . getComputedStyle ( stickyElementRef . current ) . top ?. replace ( / [ 0 - 9 ] + / g, ( match ) => {
92
- const nMatch = Number ( match )
93
- if ( Number . isNaN ( nMatch ) ) {
94
- return FALLBACK_SENTINEL_HEIGHT
95
- }
96
- return `${ nMatch + 1 } `
97
- } ) ?? FALLBACK_SENTINEL_HEIGHT )
83
+ sentinelElement . style . height = getHeightForStickyElementTopOffset < T > ( { stickyElementRef } )
98
84
99
85
stickyElementRef . current . appendChild ( sentinelElement )
100
86
@@ -114,7 +100,7 @@ const useStickyEvent = <T extends HTMLElement = HTMLDivElement>({
114
100
isNullOrUndefined ( isStickyElementMounted ) ? [ ] : [ isStickyElementMounted ] ,
115
101
)
116
102
117
- return { stickyElementRef }
103
+ return { stickyElementRef, isStuck }
118
104
}
119
105
120
106
export default useStickyEvent
0 commit comments