@@ -16,7 +16,11 @@ const useLayoutEffect =
16
16
type ScrollerProps = {
17
17
onStepChange : ( stepIndex : number ) => void
18
18
children : React . ReactNode
19
- getRootMargin ?: ( vh : number ) => string
19
+ getRootMargin ?: (
20
+ vh : number ,
21
+ triggerPosition ?: TriggerPosition
22
+ ) => string
23
+ triggerPosition ?: TriggerPosition
20
24
debug ?: boolean
21
25
}
22
26
@@ -28,30 +32,31 @@ function Scroller({
28
32
onStepChange,
29
33
children,
30
34
getRootMargin = defaultRootMargin ,
35
+ triggerPosition,
31
36
debug = false ,
32
37
} : ScrollerProps ) {
33
- const [
34
- observer ,
35
- setObserver ,
36
- ] = React . useState < IntersectionObserver > ( )
38
+ const [ observer , setObserver ] =
39
+ React . useState < IntersectionObserver > ( )
37
40
const vh = useWindowHeight ( )
38
41
39
42
useLayoutEffect ( ( ) => {
40
43
const windowHeight = vh || 0
41
- const handleIntersect : IntersectionObserverCallback = entries => {
42
- if ( debug || ( window as any ) . chDebugScroller ) {
43
- debugEntries ( entries )
44
- }
45
- entries . forEach ( entry => {
46
- if ( entry . intersectionRatio > 0 ) {
47
- const stepElement = ( entry . target as unknown ) as StepElement
48
- onStepChange ( + stepElement . stepIndex )
44
+ const handleIntersect : IntersectionObserverCallback =
45
+ entries => {
46
+ if ( debug || ( window as any ) . chDebugScroller ) {
47
+ debugEntries ( entries )
49
48
}
50
- } )
51
- }
49
+ entries . forEach ( entry => {
50
+ if ( entry . intersectionRatio > 0 ) {
51
+ const stepElement =
52
+ entry . target as unknown as StepElement
53
+ onStepChange ( + stepElement . stepIndex )
54
+ }
55
+ } )
56
+ }
52
57
const observer = newIntersectionObserver (
53
58
handleIntersect ,
54
- getRootMargin ( windowHeight )
59
+ getRootMargin ( windowHeight , triggerPosition )
55
60
)
56
61
setObserver ( observer )
57
62
@@ -85,7 +90,8 @@ function Step({
85
90
} , [ observer ] )
86
91
87
92
useLayoutEffect ( ( ) => {
88
- const stepElement = ( ref . current as unknown ) as StepElement
93
+ const stepElement =
94
+ ref . current as unknown as StepElement
89
95
stepElement . stepIndex = index
90
96
} , [ index ] )
91
97
@@ -103,6 +109,26 @@ function newIntersectionObserver(
103
109
} )
104
110
}
105
111
106
- function defaultRootMargin ( vh : number ) {
107
- return `-${ vh / 2 - 2 } px 0px`
112
+ type TriggerPosition = `${number } px` | `${number } %`
113
+
114
+ function defaultRootMargin (
115
+ vh : number ,
116
+ triggerPosition = "50%"
117
+ ) {
118
+ let y = vh * 0.5
119
+
120
+ if ( triggerPosition . endsWith ( "%" ) ) {
121
+ const percent = parseFloat (
122
+ triggerPosition . replace ( "%" , "" )
123
+ )
124
+ y = vh * ( percent / 100 )
125
+ } else if ( triggerPosition . endsWith ( "px" ) ) {
126
+ y = parseFloat ( triggerPosition . replace ( "px" , "" ) )
127
+ }
128
+
129
+ if ( y < 0 ) {
130
+ y = vh + y
131
+ }
132
+
133
+ return `-${ y - 2 } px 0px -${ vh - y - 2 } px`
108
134
}
0 commit comments