@@ -110,11 +110,7 @@ function getContainerDimensions(containerNode: Element): Dimensions {
110
110
let scroll : Position = { } ;
111
111
let isPinchZoomedIn = ( visualViewport ?. scale ?? 1 ) > 1 ;
112
112
113
- // In the case where the container is `html` or `body` and the container doesn't have something like `position: relative`,
114
- // then position absolute will be positioned relative to the viewport, also known as the `initial containing block`.
115
- // That's why we use the visual viewport instead.
116
-
117
- if ( containerNode . tagName === 'BODY' || containerNode . tagName === 'HTML' ) {
113
+ if ( containerNode . tagName === 'BODY' ) {
118
114
let documentElement = document . documentElement ;
119
115
totalWidth = documentElement . clientWidth ;
120
116
totalHeight = documentElement . clientHeight ;
@@ -183,13 +179,10 @@ function getDelta(
183
179
let boundarySize = boundaryDimensions [ AXIS_SIZE [ axis ] ] ;
184
180
// Calculate the edges of the boundary (accomodating for the boundary padding) and the edges of the overlay.
185
181
// Note that these values are with respect to the visual viewport (aka 0,0 is the top left of the viewport)
186
-
187
- let boundaryStartEdge = containerOffsetWithBoundary [ axis ] + boundaryDimensions . scroll [ AXIS [ axis ] ] + padding ;
188
- let boundaryEndEdge = containerOffsetWithBoundary [ axis ] + boundaryDimensions . scroll [ AXIS [ axis ] ] + boundarySize - padding ;
189
- // transformed value of the left edge of the overlay
190
- let startEdgeOffset = offset - containerScroll + boundaryDimensions . scroll [ AXIS [ axis ] ] + containerOffsetWithBoundary [ axis ] - boundaryDimensions [ AXIS [ axis ] ] ;
191
- // transformed value of the right edge of the overlay
192
- let endEdgeOffset = offset - containerScroll + size + boundaryDimensions . scroll [ AXIS [ axis ] ] + containerOffsetWithBoundary [ axis ] - boundaryDimensions [ AXIS [ axis ] ] ;
182
+ let boundaryStartEdge = boundaryDimensions . scroll [ AXIS [ axis ] ] + padding ;
183
+ let boundaryEndEdge = boundarySize + boundaryDimensions . scroll [ AXIS [ axis ] ] - padding ;
184
+ let startEdgeOffset = offset - containerScroll + containerOffsetWithBoundary [ axis ] - boundaryDimensions [ AXIS [ axis ] ] ;
185
+ let endEdgeOffset = offset - containerScroll + size + containerOffsetWithBoundary [ axis ] - boundaryDimensions [ AXIS [ axis ] ] ;
193
186
194
187
// If any of the overlay edges falls outside of the boundary, shift the overlay the required amount to align one of the overlay's
195
188
// edges with the closest boundary edge.
@@ -241,8 +234,7 @@ function computePosition(
241
234
containerOffsetWithBoundary : Offset ,
242
235
isContainerPositioned : boolean ,
243
236
arrowSize : number ,
244
- arrowBoundaryOffset : number ,
245
- containerDimensions : Dimensions
237
+ arrowBoundaryOffset : number
246
238
) {
247
239
let { placement, crossPlacement, axis, crossAxis, size, crossSize} = placementInfo ;
248
240
let position : Position = { } ;
@@ -263,9 +255,9 @@ function computePosition(
263
255
264
256
position [ crossAxis ] ! += crossOffset ;
265
257
266
- // overlay top or left overlapping arrow with button bottom or right
258
+ // overlay top overlapping arrow with button bottom
267
259
const minPosition = childOffset [ crossAxis ] - overlaySize [ crossSize ] + arrowSize + arrowBoundaryOffset ;
268
- // overlay bottom or right overlapping arrow with button top or left
260
+ // overlay bottom overlapping arrow with button top
269
261
const maxPosition = childOffset [ crossAxis ] + childOffset [ crossSize ] - arrowSize - arrowBoundaryOffset ;
270
262
position [ crossAxis ] = clamp ( position [ crossAxis ] ! , minPosition , maxPosition ) ;
271
263
@@ -274,8 +266,8 @@ function computePosition(
274
266
// If the container is positioned (non-static), then we use the container's actual
275
267
// height, as `bottom` will be relative to this height. But if the container is static,
276
268
// then it can only be the `document.body`, and `bottom` will be relative to _its_
277
- // container.
278
- const containerHeight = ( isContainerPositioned ? containerOffsetWithBoundary [ size ] : containerDimensions [ TOTAL_SIZE [ size ] ] ) ;
269
+ // container, which should be as large as boundaryDimensions .
270
+ const containerHeight = ( isContainerPositioned ? containerOffsetWithBoundary [ size ] : boundaryDimensions [ TOTAL_SIZE [ size ] ] ) ;
279
271
position [ FLIPPED_DIRECTION [ axis ] ] = Math . floor ( containerHeight - childOffset [ axis ] + offset ) ;
280
272
} else {
281
273
position [ axis ] = Math . floor ( childOffset [ axis ] + childOffset [ size ] + offset ) ;
@@ -291,55 +283,42 @@ function getMaxHeight(
291
283
margins : Position ,
292
284
padding : number ,
293
285
overlayHeight : number ,
294
- heightGrowthDirection : HeightGrowthDirection ,
295
- containerDimensions : Dimensions
286
+ heightGrowthDirection : HeightGrowthDirection
296
287
) {
297
- const containerHeight = ( isContainerPositioned ? containerOffsetWithBoundary . height : containerDimensions [ TOTAL_SIZE . height ] ) ;
298
- // For cases where position is set via "bottom" instead of "top", we need to calculate the true overlay top
299
- // with respect to the container .
300
- let overlayTop = position . top != null ? position . top : ( containerHeight - ( position . bottom ?? 0 ) - overlayHeight ) ;
288
+ const containerHeight = ( isContainerPositioned ? containerOffsetWithBoundary . height : boundaryDimensions [ TOTAL_SIZE . height ] ) ;
289
+ // For cases where position is set via "bottom" instead of "top", we need to calculate the true overlay top with respect to the boundary. Reverse calculate this with the same method
290
+ // used in computePosition .
291
+ let overlayTop = position . top != null ? containerOffsetWithBoundary . top + position . top : containerOffsetWithBoundary . top + ( containerHeight - ( position . bottom ?? 0 ) - overlayHeight ) ;
301
292
let maxHeight = heightGrowthDirection !== 'top' ?
302
293
// We want the distance between the top of the overlay to the bottom of the boundary
303
294
Math . max ( 0 ,
304
- ( boundaryDimensions . height + boundaryDimensions . top ) // this is the bottom of the boundary
295
+ ( boundaryDimensions . height + boundaryDimensions . top + ( boundaryDimensions . scroll . top ?? 0 ) ) // this is the bottom of the boundary
305
296
- overlayTop // this is the top of the overlay
306
297
- ( ( margins . top ?? 0 ) + ( margins . bottom ?? 0 ) + padding ) // save additional space for margin and padding
307
298
)
308
299
// We want the distance between the bottom of the overlay to the top of the boundary
309
300
: Math . max ( 0 ,
310
301
( overlayTop + overlayHeight ) // this is the bottom of the overlay
311
- - boundaryDimensions . top // this is the top of the boundary
302
+ - ( boundaryDimensions . top + ( boundaryDimensions . scroll . top ?? 0 ) ) // this is the top of the boundary
312
303
- ( ( margins . top ?? 0 ) + ( margins . bottom ?? 0 ) + padding ) // save additional space for margin and padding
313
304
) ;
314
305
return Math . min ( boundaryDimensions . height - ( padding * 2 ) , maxHeight ) ;
315
306
}
316
307
317
308
function getAvailableSpace (
318
- boundaryDimensions : Dimensions , // boundary
309
+ boundaryDimensions : Dimensions ,
319
310
containerOffsetWithBoundary : Offset ,
320
- childOffset : Offset , // trigger
321
- margins : Position , // overlay
322
- padding : number , // overlay <-> boundary
311
+ childOffset : Offset ,
312
+ margins : Position ,
313
+ padding : number ,
323
314
placementInfo : ParsedPlacement
324
315
) {
325
316
let { placement, axis, size} = placementInfo ;
326
317
if ( placement === axis ) {
327
- return Math . max ( 0 ,
328
- childOffset [ axis ] // trigger start
329
- - boundaryDimensions [ axis ] // boundary start
330
- - ( margins [ axis ] ?? 0 ) // margins usually for arrows or other decorations
331
- - margins [ FLIPPED_DIRECTION [ axis ] ]
332
- - padding ) ; // padding between overlay and boundary
318
+ return Math . max ( 0 , childOffset [ axis ] - boundaryDimensions [ axis ] - ( boundaryDimensions . scroll [ axis ] ?? 0 ) + containerOffsetWithBoundary [ axis ] - ( margins [ axis ] ?? 0 ) - margins [ FLIPPED_DIRECTION [ axis ] ] - padding ) ;
333
319
}
334
320
335
- return Math . max ( 0 ,
336
- boundaryDimensions [ size ]
337
- + boundaryDimensions [ axis ]
338
- - childOffset [ axis ]
339
- - childOffset [ size ]
340
- - ( margins [ axis ] ?? 0 )
341
- - margins [ FLIPPED_DIRECTION [ axis ] ]
342
- - padding ) ;
321
+ return Math . max ( 0 , boundaryDimensions [ size ] + boundaryDimensions [ axis ] + boundaryDimensions . scroll [ axis ] - containerOffsetWithBoundary [ axis ] - childOffset [ axis ] - childOffset [ size ] - ( margins [ axis ] ?? 0 ) - margins [ FLIPPED_DIRECTION [ axis ] ] - padding ) ;
343
322
}
344
323
345
324
export function calculatePositionInternal (
@@ -362,7 +341,7 @@ export function calculatePositionInternal(
362
341
) : PositionResult {
363
342
let placementInfo = parsePlacement ( placementInput ) ;
364
343
let { size, crossAxis, crossSize, placement, crossPlacement} = placementInfo ;
365
- let position = computePosition ( childOffset , boundaryDimensions , overlaySize , placementInfo , offset , crossOffset , containerOffsetWithBoundary , isContainerPositioned , arrowSize , arrowBoundaryOffset , containerDimensions ) ;
344
+ let position = computePosition ( childOffset , boundaryDimensions , overlaySize , placementInfo , offset , crossOffset , containerOffsetWithBoundary , isContainerPositioned , arrowSize , arrowBoundaryOffset ) ;
366
345
let normalizedOffset = offset ;
367
346
let space = getAvailableSpace (
368
347
boundaryDimensions ,
@@ -376,8 +355,7 @@ export function calculatePositionInternal(
376
355
// Check if the scroll size of the overlay is greater than the available space to determine if we need to flip
377
356
if ( flip && scrollSize [ size ] > space ) {
378
357
let flippedPlacementInfo = parsePlacement ( `${ FLIPPED_DIRECTION [ placement ] } ${ crossPlacement } ` as Placement ) ;
379
- let flippedPosition = computePosition ( childOffset , boundaryDimensions , overlaySize , flippedPlacementInfo , offset , crossOffset , containerOffsetWithBoundary , isContainerPositioned , arrowSize , arrowBoundaryOffset , containerDimensions ) ;
380
-
358
+ let flippedPosition = computePosition ( childOffset , boundaryDimensions , overlaySize , flippedPlacementInfo , offset , crossOffset , containerOffsetWithBoundary , isContainerPositioned , arrowSize , arrowBoundaryOffset ) ;
381
359
let flippedSpace = getAvailableSpace (
382
360
boundaryDimensions ,
383
361
containerOffsetWithBoundary ,
@@ -422,8 +400,7 @@ export function calculatePositionInternal(
422
400
margins ,
423
401
padding ,
424
402
overlaySize . height ,
425
- heightGrowthDirection ,
426
- containerDimensions
403
+ heightGrowthDirection
427
404
) ;
428
405
429
406
if ( userSetMaxHeight && userSetMaxHeight < maxHeight ) {
@@ -432,7 +409,7 @@ export function calculatePositionInternal(
432
409
433
410
overlaySize . height = Math . min ( overlaySize . height , maxHeight ) ;
434
411
435
- position = computePosition ( childOffset , boundaryDimensions , overlaySize , placementInfo , normalizedOffset , crossOffset , containerOffsetWithBoundary , isContainerPositioned , arrowSize , arrowBoundaryOffset , containerDimensions ) ;
412
+ position = computePosition ( childOffset , boundaryDimensions , overlaySize , placementInfo , normalizedOffset , crossOffset , containerOffsetWithBoundary , isContainerPositioned , arrowSize , arrowBoundaryOffset ) ;
436
413
delta = getDelta ( crossAxis , position [ crossAxis ] ! , overlaySize [ crossSize ] , boundaryDimensions , containerDimensions , padding , containerOffsetWithBoundary ) ;
437
414
position [ crossAxis ] ! += delta ;
438
415
@@ -530,7 +507,7 @@ export function calculatePosition(opts: PositionOpts): PositionResult {
530
507
// If the container is the HTML element wrapping the body element, the retrieved scrollTop/scrollLeft will be equal to the
531
508
// body element's scroll. Set the container's scroll values to 0 since the overlay's edge position value in getDelta don't then need to be further offset
532
509
// by the container scroll since they are essentially the same containing element and thus in the same coordinate system
533
- let containerOffsetWithBoundary : Offset = boundaryElement . tagName === 'BODY' ? getOffset ( container , false ) : getPosition ( boundaryElement , container , false ) ;
510
+ let containerOffsetWithBoundary : Offset = boundaryElement . tagName === 'BODY' ? getOffset ( container , false ) : getPosition ( container , boundaryElement , false ) ;
534
511
if ( container . tagName === 'HTML' && boundaryElement . tagName === 'BODY' ) {
535
512
containerDimensions . scroll . top = 0 ;
536
513
containerDimensions . scroll . left = 0 ;
@@ -559,7 +536,7 @@ export function calculatePosition(opts: PositionOpts): PositionResult {
559
536
export function getRect ( node : Element , ignoreScale : boolean ) {
560
537
let { top, left, width, height} = node . getBoundingClientRect ( ) ;
561
538
562
- // Use offsetWidth and offsetHeight if this is an HTML element, so that
539
+ // Use offsetWidth and offsetHeight if this is an HTML element, so that
563
540
// the size is not affected by scale transforms.
564
541
if ( ignoreScale && node instanceof node . ownerDocument . defaultView ! . HTMLElement ) {
565
542
width = node . offsetWidth ;
0 commit comments