@@ -26,6 +26,16 @@ export const hydrateOnIdle: HydrationStrategyFactory<number> =
26
26
return ( ) => cancelIdleCallback ( id )
27
27
}
28
28
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
+
29
39
export const hydrateOnVisible : HydrationStrategyFactory <
30
40
IntersectionObserverInit
31
41
> = opts => ( hydrate , forEach ) => {
@@ -37,7 +47,14 @@ export const hydrateOnVisible: HydrationStrategyFactory<
37
47
break
38
48
}
39
49
} , 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
+ } )
41
58
return ( ) => ob . disconnect ( )
42
59
}
43
60
@@ -85,14 +102,20 @@ export const hydrateOnInteraction: HydrationStrategyFactory<
85
102
return teardown
86
103
}
87
104
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 {
89
109
// fragment
90
110
if ( isComment ( node ) && node . data === '[' ) {
91
111
let depth = 1
92
112
let next = node . nextSibling
93
113
while ( next ) {
94
114
if ( next . nodeType === DOMNodeTypes . ELEMENT ) {
95
- cb ( next as Element )
115
+ const result = cb ( next as Element )
116
+ if ( result === false ) {
117
+ break
118
+ }
96
119
} else if ( isComment ( next ) ) {
97
120
if ( next . data === ']' ) {
98
121
if ( -- depth === 0 ) break
0 commit comments