@@ -26,6 +26,16 @@ export const hydrateOnIdle: HydrationStrategyFactory<number> =
2626 return ( ) => cancelIdleCallback ( id )
2727 }
2828
29+ function elementIsVisibleInViewport ( el : Element ) {
30+ const { top, left, bottom, right } = el . getBoundingClientRect ( )
31+ // eslint-disable-next-line no-restricted-globals
32+ const { innerHeight, innerWidth } = window
33+ return (
34+ ( ( top > 0 && top < innerHeight ) || ( bottom > 0 && bottom < innerHeight ) ) &&
35+ ( ( left > 0 && left < innerWidth ) || ( right > 0 && right < innerWidth ) )
36+ )
37+ }
38+
2939export const hydrateOnVisible : HydrationStrategyFactory <
3040 IntersectionObserverInit
3141> = opts => ( hydrate , forEach ) => {
@@ -37,7 +47,14 @@ export const hydrateOnVisible: HydrationStrategyFactory<
3747 break
3848 }
3949 } , opts )
40- forEach ( el => ob . observe ( el ) )
50+ forEach ( el => {
51+ if ( elementIsVisibleInViewport ( el ) ) {
52+ hydrate ( )
53+ ob . disconnect ( )
54+ return false
55+ }
56+ ob . observe ( el )
57+ } )
4158 return ( ) => ob . disconnect ( )
4259}
4360
@@ -85,14 +102,20 @@ export const hydrateOnInteraction: HydrationStrategyFactory<
85102 return teardown
86103 }
87104
88- export function forEachElement ( node : Node , cb : ( el : Element ) => void ) : void {
105+ export function forEachElement (
106+ node : Node ,
107+ cb : ( el : Element ) => void | false ,
108+ ) : void {
89109 // fragment
90110 if ( isComment ( node ) && node . data === '[' ) {
91111 let depth = 1
92112 let next = node . nextSibling
93113 while ( next ) {
94114 if ( next . nodeType === DOMNodeTypes . ELEMENT ) {
95- cb ( next as Element )
115+ const result = cb ( next as Element )
116+ if ( result === false ) {
117+ break
118+ }
96119 } else if ( isComment ( next ) ) {
97120 if ( next . data === ']' ) {
98121 if ( -- depth === 0 ) break
0 commit comments