1- type ElementSelector = HTMLElement | string ;
2-
31/**
42 * Sticky positioning options.
53 */
@@ -34,6 +32,8 @@ export const ADHESIVE_STATUS = {
3432export type AdhesiveStatus =
3533 ( typeof ADHESIVE_STATUS ) [ keyof typeof ADHESIVE_STATUS ] ;
3634
35+ type ElementSelector = HTMLElement | string ;
36+
3737/**
3838 * Configuration options for Adhesive instances.
3939 */
@@ -177,11 +177,39 @@ const DEFAULT_OPTIONS = {
177177const isBrowser = ( ) =>
178178 typeof window !== "undefined" && typeof document !== "undefined" ;
179179
180- const resolveElement = ( element : ElementSelector ) : HTMLElement | null => {
180+ const resolveElement = ( selector : ElementSelector ) : HTMLElement | null => {
181181 if ( ! isBrowser ( ) ) return null ;
182- return typeof element === "string"
183- ? document . querySelector ( element )
184- : element ;
182+ return typeof selector === "string"
183+ ? document . querySelector ( selector )
184+ : selector ;
185+ } ;
186+
187+ const assertTargetElement = (
188+ selector : AdhesiveOptions [ "targetEl" ] ,
189+ ) : HTMLElement => {
190+ if ( ! isBrowser ( ) ) return Object . create ( null ) ;
191+
192+ const element = resolveElement ( selector ) ;
193+
194+ if ( ! element ) {
195+ throw new AdhesiveError ( "TARGET_EL_NOT_FOUND" , "targetEl not found" ) ;
196+ }
197+
198+ return element ;
199+ } ;
200+
201+ const assertBoundingElement = (
202+ selector : AdhesiveOptions [ "boundingEl" ] | undefined ,
203+ ) : HTMLElement => {
204+ if ( ! isBrowser ( ) ) return Object . create ( null ) ;
205+
206+ const element = selector ? resolveElement ( selector ) : document . body ;
207+
208+ if ( ! element ) {
209+ throw new AdhesiveError ( "BOUNDING_EL_NOT_FOUND" , "boundingEl not found" ) ;
210+ }
211+
212+ return element ;
185213} ;
186214
187215const getScrollTop = ( ) =>
@@ -299,26 +327,11 @@ export class Adhesive {
299327
300328 this . #targetElSelector = options . targetEl ;
301329 this . #boundingElSelector = options . boundingEl ?? null ;
330+ this . #targetEl = assertTargetElement ( this . #targetElSelector) ;
331+ this . #boundingEl = assertBoundingElement ( this . #boundingElSelector) ;
302332
303- if ( ! isBrowser ( ) ) {
304- this . #targetEl = this . #boundingEl = Object . create ( null ) ;
305- return ;
306- }
307-
308- const targetEl = resolveElement ( options . targetEl ) ;
309- const boundingEl = options . boundingEl
310- ? resolveElement ( options . boundingEl )
311- : document . body ;
312-
313- if ( ! targetEl ) {
314- throw new AdhesiveError ( "TARGET_EL_NOT_FOUND" , "targetEl not found" ) ;
315- }
316- if ( ! boundingEl ) {
317- throw new AdhesiveError ( "BOUNDING_EL_NOT_FOUND" , "boundingEl not found" ) ;
318- }
333+ if ( ! isBrowser ( ) ) return ;
319334
320- this . #targetEl = targetEl ;
321- this . #boundingEl = boundingEl ;
322335 this . #options. enabled = options . enabled ?? DEFAULT_OPTIONS . enabled ;
323336 this . #options. offset = options . offset ?? DEFAULT_OPTIONS . offset ;
324337 this . #options. position = options . position ?? DEFAULT_OPTIONS . position ;
@@ -361,26 +374,8 @@ export class Adhesive {
361374 if ( ! this . #outerWrapper && ! this . #innerWrapper) {
362375 // Re-resolve elements if transitioning from SSR to browser
363376 if ( ! this . #targetEl. parentNode ) {
364- const targetEl = resolveElement ( this . #targetElSelector) ;
365- const boundingEl = this . #boundingElSelector
366- ? resolveElement ( this . #boundingElSelector)
367- : document . body ;
368-
369- if ( ! targetEl ) {
370- throw new AdhesiveError (
371- "TARGET_EL_NOT_FOUND" ,
372- "targetEl not found" ,
373- ) ;
374- }
375- if ( ! boundingEl ) {
376- throw new AdhesiveError (
377- "BOUNDING_EL_NOT_FOUND" ,
378- "boundingEl not found" ,
379- ) ;
380- }
381-
382- this . #targetEl = targetEl ;
383- this . #boundingEl = boundingEl ;
377+ this . #targetEl = assertTargetElement ( this . #targetElSelector) ;
378+ this . #boundingEl = assertBoundingElement ( this . #boundingElSelector) ;
384379 }
385380
386381 this . #createWrappers( ) ;
@@ -405,12 +400,14 @@ export class Adhesive {
405400 /**
406401 * Update configuration options (partial update).
407402 */
408- updateOptions (
409- newOptions : Partial < Omit < AdhesiveOptions , "targetEl" | "boundingEl" > > ,
410- ) : this {
403+ updateOptions ( newOptions : Partial < Omit < AdhesiveOptions , "targetEl" > > ) : this {
411404 if ( newOptions . enabled === false ) return this . disable ( ) ;
412405 if ( newOptions . enabled === true ) this . enable ( ) ;
413406
407+ const currentBoundingEl = this . #boundingEl;
408+
409+ if ( newOptions . boundingEl !== undefined )
410+ this . #boundingEl = assertBoundingElement ( newOptions . boundingEl ) ;
414411 if ( newOptions . offset !== undefined )
415412 this . #options. offset = newOptions . offset ;
416413 if ( newOptions . position ) this . #options. position = newOptions . position ;
@@ -427,6 +424,8 @@ export class Adhesive {
427424 if ( newOptions . relativeClassName !== undefined )
428425 this . #options. relativeClassName = newOptions . relativeClassName ;
429426
427+ if ( currentBoundingEl !== this . #boundingEl) this . #refreshListeners( ) ;
428+
430429 this . #update( ) ;
431430 this . #rerender( ) ;
432431 return this ;
@@ -435,12 +434,13 @@ export class Adhesive {
435434 /**
436435 * Replace configuration options (full update).
437436 */
438- replaceOptions (
439- newOptions : Omit < AdhesiveOptions , "targetEl" | "boundingEl" > ,
440- ) : this {
437+ replaceOptions ( newOptions : Omit < AdhesiveOptions , "targetEl" > ) : this {
441438 if ( newOptions . enabled === false ) return this . disable ( ) ;
442439 if ( newOptions . enabled === true ) this . enable ( ) ;
443440
441+ const currentBoundingEl = this . #boundingEl;
442+
443+ this . #boundingEl = assertBoundingElement ( newOptions . boundingEl ) ;
444444 this . #options. offset = newOptions . offset ?? DEFAULT_OPTIONS . offset ;
445445 this . #options. position = newOptions . position ?? DEFAULT_OPTIONS . position ;
446446 this . #options. zIndex = newOptions . zIndex ?? DEFAULT_OPTIONS . zIndex ;
@@ -455,6 +455,8 @@ export class Adhesive {
455455 this . #options. relativeClassName =
456456 newOptions . relativeClassName ?? DEFAULT_OPTIONS . relativeClassName ;
457457
458+ if ( currentBoundingEl !== this . #boundingEl) this . #refreshListeners( ) ;
459+
458460 this . #update( ) ;
459461 this . #rerender( ) ;
460462 return this ;
@@ -482,11 +484,7 @@ export class Adhesive {
482484 if ( ! isBrowser ( ) ) return ;
483485
484486 this . #cancelRAF( ) ;
485- window . removeEventListener ( "scroll" , this . #onScroll) ;
486- window . removeEventListener ( "resize" , this . #onResize) ;
487- this . #observer?. disconnect ( ) ;
488- this . #observer = null ;
489- this . #trackedElements. clear ( ) ;
487+ this . #cleanupListeners( ) ;
490488 this . #setInitial( ) ;
491489 this . #state. activated = false ;
492490
@@ -528,6 +526,8 @@ export class Adhesive {
528526 }
529527
530528 #setupListeners( ) : void {
529+ if ( ! isBrowser ( ) ) return ;
530+
531531 window . addEventListener ( "scroll" , this . #onScroll, { passive : true } ) ;
532532 window . addEventListener ( "resize" , this . #onResize, { passive : true } ) ;
533533
@@ -547,6 +547,23 @@ export class Adhesive {
547547 }
548548 }
549549
550+ #cleanupListeners( ) : void {
551+ if ( ! isBrowser ( ) ) return ;
552+
553+ window . removeEventListener ( "scroll" , this . #onScroll) ;
554+ window . removeEventListener ( "resize" , this . #onResize) ;
555+ this . #observer?. disconnect ( ) ;
556+ this . #observer = null ;
557+ this . #trackedElements. clear ( ) ;
558+ }
559+
560+ #refreshListeners( ) : void {
561+ if ( ! isBrowser ( ) ) return ;
562+
563+ this . #cleanupListeners( ) ;
564+ this . #setupListeners( ) ;
565+ }
566+
550567 #onScroll = ( ) : void => {
551568 this . #scheduleUpdate( ) ;
552569 } ;
@@ -625,15 +642,15 @@ export class Adhesive {
625642 }
626643
627644 #getTopBoundary( ) : number {
628- if ( ! isBrowser ( ) || this . #boundingEl === document . body ) return 0 ;
645+ if ( this . #boundingEl === document . body ) return 0 ;
646+
629647 const rect = this . #boundingEl. getBoundingClientRect ( ) ;
630648 return getScrollTop ( ) + rect . top ;
631649 }
632650
633651 #getBottomBoundary( ) : number {
634- if ( ! isBrowser ( ) || this . #boundingEl === document . body ) {
635- return Number . POSITIVE_INFINITY ;
636- }
652+ if ( this . #boundingEl === document . body ) return Number . POSITIVE_INFINITY ;
653+
637654 const rect = this . #boundingEl. getBoundingClientRect ( ) ;
638655 return getScrollTop ( ) + rect . bottom ;
639656 }
0 commit comments