@@ -83,7 +83,7 @@ export class PositionedOverlay extends PureComponent<
83
83
} ;
84
84
85
85
private overlay : HTMLElement | null = null ;
86
- private scrollableContainer : HTMLElement | Document | null = null ;
86
+ private scrollableContainers : ( HTMLElement | Document ) [ ] = [ ] ;
87
87
private observer : MutationObserver ;
88
88
89
89
constructor ( props : PositionedOverlayProps ) {
@@ -93,23 +93,20 @@ export class PositionedOverlay extends PureComponent<
93
93
}
94
94
95
95
componentDidMount ( ) {
96
- this . scrollableContainer = Scrollable . forNode ( this . props . activator ) ;
97
- if ( this . scrollableContainer && ! this . props . fixed ) {
98
- this . scrollableContainer . addEventListener (
99
- 'scroll' ,
100
- this . handleMeasurement ,
101
- ) ;
96
+ this . setScrollableContainers ( ) ;
97
+
98
+ if ( this . scrollableContainers . length && ! this . props . fixed ) {
99
+ this . registerScrollHandlers ( ) ;
102
100
}
101
+
103
102
this . handleMeasurement ( ) ;
104
103
}
105
104
106
105
componentWillUnmount ( ) {
107
106
this . observer . disconnect ( ) ;
108
- if ( this . scrollableContainer && ! this . props . fixed ) {
109
- this . scrollableContainer . removeEventListener (
110
- 'scroll' ,
111
- this . handleMeasurement ,
112
- ) ;
107
+
108
+ if ( this . scrollableContainers . length && ! this . props . fixed ) {
109
+ this . unregisterScrollHandlers ( ) ;
113
110
}
114
111
}
115
112
@@ -160,6 +157,10 @@ export class PositionedOverlay extends PureComponent<
160
157
) ;
161
158
}
162
159
160
+ get firstScrollableContainer ( ) : HTMLElement | Document | null {
161
+ return this . scrollableContainers [ 0 ] ?? null ;
162
+ }
163
+
163
164
forceUpdatePosition ( ) {
164
165
// Wait a single animation frame before re-measuring.
165
166
// Consumer's may also need to setup their own timers for
@@ -186,6 +187,37 @@ export class PositionedOverlay extends PureComponent<
186
187
this . overlay = node ;
187
188
} ;
188
189
190
+ private setScrollableContainers = ( ) => {
191
+ const containers : ( HTMLElement | Document ) [ ] = [ ] ;
192
+ let scrollableContainer = Scrollable . forNode ( this . props . activator ) ;
193
+
194
+ if ( scrollableContainer ) {
195
+ containers . push ( scrollableContainer ) ;
196
+
197
+ while ( scrollableContainer ?. parentElement ) {
198
+ scrollableContainer = Scrollable . forNode (
199
+ scrollableContainer . parentElement ,
200
+ ) ;
201
+
202
+ containers . push ( scrollableContainer ) ;
203
+ }
204
+ }
205
+
206
+ this . scrollableContainers = containers ;
207
+ } ;
208
+
209
+ private registerScrollHandlers = ( ) => {
210
+ this . scrollableContainers . forEach ( ( node ) => {
211
+ node . addEventListener ( 'scroll' , this . handleMeasurement ) ;
212
+ } ) ;
213
+ } ;
214
+
215
+ private unregisterScrollHandlers = ( ) => {
216
+ this . scrollableContainers . forEach ( ( node ) => {
217
+ node . removeEventListener ( 'scroll' , this . handleMeasurement ) ;
218
+ } ) ;
219
+ } ;
220
+
189
221
private handleMeasurement = ( ) => {
190
222
const { lockPosition, top} = this . state ;
191
223
@@ -201,7 +233,7 @@ export class PositionedOverlay extends PureComponent<
201
233
measuring : true ,
202
234
} ) ,
203
235
( ) => {
204
- if ( this . overlay == null || this . scrollableContainer == null ) {
236
+ if ( this . overlay == null || this . firstScrollableContainer == null ) {
205
237
return ;
206
238
}
207
239
@@ -222,9 +254,9 @@ export class PositionedOverlay extends PureComponent<
222
254
const activatorRect = getRectForNode ( preferredActivator ) ;
223
255
224
256
const currentOverlayRect = getRectForNode ( this . overlay ) ;
225
- const scrollableElement = isDocument ( this . scrollableContainer )
257
+ const scrollableElement = isDocument ( this . firstScrollableContainer )
226
258
? document . body
227
- : this . scrollableContainer ;
259
+ : this . firstScrollableContainer ;
228
260
const scrollableContainerRect = getRectForNode ( scrollableElement ) ;
229
261
230
262
const overlayRect = fullWidth
0 commit comments