1- import { useState , useEffect , useMemo , useCallback , useRef , Children , cloneElement , useContext } from 'react' ;
1+ import {
2+ useState ,
3+ useEffect ,
4+ useMemo ,
5+ useCallback ,
6+ useRef ,
7+ Children ,
8+ cloneElement ,
9+ useContext ,
10+ useLayoutEffect ,
11+ } from 'react' ;
212import { useInView } from 'react-intersection-observer' ;
313
414import { isBrowser , getRootMargin , getProgressRootMargin } from './utils' ;
5- import type { StepProps } from './types' ;
15+ import type { StepProps , ScrollamaCallbackData } from './types' ;
616import { ScrollamaProvide } from './provide' ;
717
818export const Step : React . FC < StepProps > = ( {
@@ -20,6 +30,7 @@ export const Step: React.FC<StepProps> = ({
2030 innerHeight = 0 ,
2131 } = useContext ( ScrollamaProvide ) ;
2232
33+ const [ nodeOffsetHeight , setNodeOffsetHeight ] = useState ( 0 ) ;
2334 const rootMargin = getRootMargin ( { offset } ) ;
2435 const { ref : inViewRef , entry } = useInView ( {
2536 rootMargin,
@@ -33,9 +44,10 @@ export const Step: React.FC<StepProps> = ({
3344 const ref = useRef < HTMLElement | null > ( null ) ;
3445 const [ isIntersecting , setIsIntersecting ] = useState ( false ) ;
3546
47+
3648 const progressRootMargin = useMemo (
37- ( ) => getProgressRootMargin ( { direction, offset, node : ref , innerHeight } ) ,
38- [ direction , offset , ref , innerHeight ]
49+ ( ) => getProgressRootMargin ( { direction, offset, nodeOffsetHeight , innerHeight } ) ,
50+ [ direction , offset , nodeOffsetHeight , innerHeight ]
3951 ) ;
4052
4153 const { ref : scrollProgressRef , entry : scrollProgressEntry } = useInView ( {
@@ -55,7 +67,7 @@ export const Step: React.FC<StepProps> = ({
5567
5668 useEffect ( ( ) => {
5769 if ( isIntersecting && scrollProgressEntry ) {
58- const { height, top } = scrollProgressEntry . target . getBoundingClientRect ( ) ;
70+ const { height, top } = scrollProgressEntry . boundingClientRect ;
5971 const progress = Math . min ( 1 , Math . max ( 0 , ( window . innerHeight * offset - top ) / height ) ) ;
6072 if ( onStepProgress ) {
6173 onStepProgress ( {
@@ -70,22 +82,29 @@ export const Step: React.FC<StepProps> = ({
7082 } , [ scrollProgressEntry ] ) ;
7183
7284 useEffect ( ( ) => {
73- if ( entry && ! entry . isIntersecting && isIntersecting ) {
74- setIsIntersecting ( false ) ;
75- onStepExit ( { element : entry . target , data, entry, direction } ) ;
76- handleSetLastScrollTop ( scrollTop )
77- } else if ( entry && entry . isIntersecting && ! isIntersecting ) {
78- setIsIntersecting ( true ) ;
79- onStepEnter ( { element : entry . target , data, entry, direction } ) ;
80- handleSetLastScrollTop ( scrollTop )
85+ if ( entry ) {
86+ const currentIntersectionState = entry . isIntersecting ;
87+ if ( currentIntersectionState !== isIntersecting ) {
88+ setIsIntersecting ( currentIntersectionState ) ;
89+ const eventData : ScrollamaCallbackData < unknown > = { element : entry . target , data, entry, direction } ;
90+ if ( currentIntersectionState ) {
91+ onStepEnter ( eventData ) ;
92+ } else {
93+ onStepExit ( eventData ) ;
94+ }
95+ handleSetLastScrollTop ( scrollTop ) ;
96+ }
8197 }
8298 } , [ entry ] ) ;
8399
100+ useLayoutEffect ( ( ) => {
101+ if ( ref . current ) {
102+ setNodeOffsetHeight ( ref . current . offsetHeight ) ;
103+ }
104+ } , [ ref . current ] ) ;
105+
84106 const childElement = Children . only ( children ) ;
85- return cloneElement ( childElement , {
86- ref : setRefs ,
87- entry,
88- } ) ;
107+ return cloneElement ( childElement , { ref : setRefs } ) ;
89108} ;
90109
91110
0 commit comments