@@ -19,7 +19,7 @@ const hoverTriggers = new WeakMap<Element, DeferEventEntry>();
1919const interactionTriggers = new WeakMap < Element , DeferEventEntry > ( ) ;
2020
2121/** Currently-registered `viewport` triggers. */
22- export const viewportTriggers = new WeakMap < Element , DeferEventEntry > ( ) ;
22+ export const viewportTriggers = new WeakMap < Element , Map < string , DeferEventEntry > > ( ) ;
2323
2424/** Names of the events considered as interaction events. */
2525export const interactionEventNames = [ 'click' , 'keydown' ] as const ;
@@ -28,10 +28,7 @@ export const interactionEventNames = ['click', 'keydown'] as const;
2828export const hoverEventNames = [ 'mouseenter' , 'mouseover' , 'focusin' ] as const ;
2929
3030/** `IntersectionObserver` used to observe `viewport` triggers. */
31- let intersectionObserver : IntersectionObserver | null = null ;
32-
33- /** Number of elements currently observed with `viewport` triggers. */
34- let observedViewportElements = 0 ;
31+ const intersectionObservers = new Map < string , { observer : IntersectionObserver ; count : number } > ( ) ;
3532
3633/** Object keeping track of registered callbacks for a deferred block trigger. */
3734class DeferEventEntry {
@@ -130,14 +127,15 @@ export function onHover(trigger: Element, callback: VoidFunction): VoidFunction
130127 * Used to create an IntersectionObserver instance.
131128 * @return IntersectionObserver that is used by onViewport
132129 */
133- export function createIntersectionObserver ( ) {
130+ export function createIntersectionObserver ( options ?: IntersectionObserverInit ) {
131+ const key = getIntersectionObserverKey ( options ) ;
134132 return new IntersectionObserver ( ( entries ) => {
135133 for ( const current of entries ) {
136134 if ( current . isIntersecting && viewportTriggers . has ( current . target ) ) {
137- viewportTriggers . get ( current . target ) ! . listener ( ) ;
135+ viewportTriggers . get ( current . target ) ?. get ( key ) ? .listener ( ) ;
138136 }
139137 }
140- } ) ;
138+ } , options ) ;
141139}
142140
143141/**
@@ -152,37 +150,71 @@ export function createIntersectionObserver() {
152150export function onViewport (
153151 trigger : Element ,
154152 callback : VoidFunction ,
155- observerFactoryFn : ( ) => IntersectionObserver ,
153+ observerFactoryFn : ( options ?: IntersectionObserverInit ) => IntersectionObserver ,
154+ options ?: IntersectionObserverInit ,
156155) : VoidFunction {
157- let entry = viewportTriggers . get ( trigger ) ;
156+ const key = getIntersectionObserverKey ( options ) ;
157+ let entry = viewportTriggers . get ( trigger ) ?. get ( key ) ;
158+
159+ if ( ! intersectionObservers . has ( key ) ) {
160+ intersectionObservers . set ( key , { observer : observerFactoryFn ( options ) , count : 0 } ) ;
161+ }
158162
159- intersectionObserver = intersectionObserver || observerFactoryFn ( ) ;
163+ const config = intersectionObservers . get ( key ) ! ;
160164
161165 if ( ! entry ) {
162166 entry = new DeferEventEntry ( ) ;
163- intersectionObserver ! . observe ( trigger ) ;
164- viewportTriggers . set ( trigger , entry ) ;
165- observedViewportElements ++ ;
167+ config . observer . observe ( trigger ) ;
168+
169+ let triggerConfig = viewportTriggers . get ( trigger ) ;
170+
171+ if ( triggerConfig ) {
172+ triggerConfig . set ( key , entry ) ;
173+ } else {
174+ triggerConfig = new Map ( ) ;
175+ viewportTriggers . set ( trigger , triggerConfig ) ;
176+ }
177+
178+ triggerConfig . set ( key , entry ) ;
179+ config . count ++ ;
166180 }
167181
168182 entry . callbacks . add ( callback ) ;
169183
170184 return ( ) => {
171- if ( ! viewportTriggers . has ( trigger ) ) {
185+ if ( ! viewportTriggers . get ( trigger ) ?. has ( key ) ) {
172186 return ;
173187 }
174188
175189 entry ! . callbacks . delete ( callback ) ;
176190
177191 if ( entry ! . callbacks . size === 0 ) {
178- intersectionObserver ?. unobserve ( trigger ) ;
179- viewportTriggers . delete ( trigger ) ;
180- observedViewportElements -- ;
192+ config . observer . unobserve ( trigger ) ;
193+ config . count -- ;
194+
195+ const triggerConfig = viewportTriggers . get ( trigger ) ;
196+
197+ if ( triggerConfig ) {
198+ triggerConfig . delete ( key ) ;
199+
200+ if ( triggerConfig . size === 0 ) {
201+ viewportTriggers . delete ( trigger ) ;
202+ }
203+ }
181204 }
182205
183- if ( observedViewportElements === 0 ) {
184- intersectionObserver ? .disconnect ( ) ;
185- intersectionObserver = null ;
206+ if ( config . count === 0 ) {
207+ config . observer . disconnect ( ) ;
208+ intersectionObservers . delete ( key ) ;
186209 }
187210 } ;
188211}
212+
213+ /** Generates a string that can be used to find identical intersection observer option objects. */
214+ function getIntersectionObserverKey ( options : IntersectionObserverInit | undefined ) : string {
215+ if ( ! options ) {
216+ return '' ;
217+ }
218+
219+ return `${ options . rootMargin } /${ typeof options . threshold === 'number' ? options . threshold : options . threshold ?. join ( '\n' ) } ` ;
220+ }
0 commit comments