@@ -69,6 +69,7 @@ export class UUIPopoverContainerElement extends LitElement {
69
69
_actualPlacement : PopoverContainerPlacement = this . _placement ;
70
70
71
71
#targetElement: HTMLElement | null = null ;
72
+ #scrollParents: Element [ ] = [ ] ;
72
73
73
74
connectedCallback ( ) : void {
74
75
//TODO: Remove this polyfill when firefox supports the new popover API
@@ -85,6 +86,7 @@ export class UUIPopoverContainerElement extends LitElement {
85
86
disconnectedCallback ( ) : void {
86
87
super . disconnectedCallback ( ) ;
87
88
this . removeEventListener ( 'beforetoggle' , this . #onBeforeToggle) ;
89
+ this . #stopScrollListener( ) ;
88
90
}
89
91
90
92
#onBeforeToggle = ( event : any ) => {
@@ -96,6 +98,8 @@ export class UUIPopoverContainerElement extends LitElement {
96
98
this . id
97
99
) ;
98
100
101
+ this . #getScrollParents( ) ;
102
+
99
103
// Dispatch a custom event that can be listened to by the popover target.
100
104
// Mostly used for UUIButton.
101
105
this . #targetElement?. dispatchEvent (
@@ -110,11 +114,11 @@ export class UUIPopoverContainerElement extends LitElement {
110
114
) ;
111
115
112
116
if ( ! this . _open ) {
113
- document . removeEventListener ( 'scroll' , this . #initUpdate ) ;
117
+ this . #stopScrollListener ( ) ;
114
118
return ;
115
119
}
116
120
117
- document . addEventListener ( 'scroll' , this . #initUpdate ) ;
121
+ this . #startScrollListener ( ) ;
118
122
119
123
requestAnimationFrame ( ( ) => {
120
124
this . #initUpdate( ) ;
@@ -305,6 +309,52 @@ export class UUIPopoverContainerElement extends LitElement {
305
309
`${ oppositeDirection } -${ position } ` as PopoverContainerPlacement ;
306
310
}
307
311
312
+ #startScrollListener( ) {
313
+ this . #scrollParents. forEach ( el => {
314
+ el . addEventListener ( 'scroll' , this . #initUpdate, { passive : true } ) ;
315
+ } ) ;
316
+ document . addEventListener ( 'scroll' , this . #initUpdate, { passive : true } ) ;
317
+ }
318
+ #stopScrollListener( ) {
319
+ this . #scrollParents. forEach ( el => {
320
+ el . removeEventListener ( 'scroll' , this . #initUpdate) ;
321
+ } ) ;
322
+ document . removeEventListener ( 'scroll' , this . #initUpdate) ;
323
+ }
324
+
325
+ #getScrollParents( ) : any {
326
+ if ( ! this . #targetElement) return ;
327
+
328
+ let style = getComputedStyle ( this . #targetElement) ;
329
+ if ( style . position === 'fixed' ) {
330
+ return ;
331
+ }
332
+
333
+ const includeHidden = false ;
334
+ const excludeStaticParent = style . position === 'absolute' ;
335
+ const overflowRegex = includeHidden
336
+ ? / ( a u t o | s c r o l l | h i d d e n ) /
337
+ : / ( a u t o | s c r o l l ) / ;
338
+
339
+ let el = this . #targetElement;
340
+ while ( ( el = el . parentElement as HTMLElement ) ) {
341
+ style = getComputedStyle ( el ) ;
342
+
343
+ if ( excludeStaticParent && style . position === 'static' ) {
344
+ continue ;
345
+ }
346
+ if (
347
+ overflowRegex . test ( style . overflow + style . overflowY + style . overflowX )
348
+ ) {
349
+ this . #scrollParents. push ( el ) ;
350
+ }
351
+ if ( style . position === 'fixed' ) {
352
+ return ;
353
+ }
354
+ }
355
+ this . #scrollParents. push ( document . body ) ;
356
+ }
357
+
308
358
render ( ) {
309
359
return html `<slot> </ slot> ` ;
310
360
}
0 commit comments