Skip to content

Commit 2b673bb

Browse files
committed
try to determine when scrolling distance should be taken into consideration
1 parent 86fe2a7 commit 2b673bb

File tree

1 file changed

+21
-17
lines changed

1 file changed

+21
-17
lines changed

packages/@react-aria/overlays/src/calculatePosition.ts

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -301,14 +301,14 @@ function getMaxHeight(
301301
let maxHeight = heightGrowthDirection !== 'top' ?
302302
// We want the distance between the top of the overlay to the bottom of the boundary
303303
Math.max(0,
304-
(boundaryDimensions.height + boundaryDimensions.top) // this is the bottom of the boundary
304+
(boundaryDimensions.height + boundaryDimensions.top + (boundaryDimensions.scroll.top ?? 0)) // this is the bottom of the boundary
305305
- overlayTop // this is the top of the overlay
306306
- ((margins.top ?? 0) + (margins.bottom ?? 0) + padding) // save additional space for margin and padding
307307
)
308308
// We want the distance between the bottom of the overlay to the top of the boundary
309309
: Math.max(0,
310310
(overlayTop + overlayHeight) // this is the bottom of the overlay
311-
- boundaryDimensions.top // this is the top of the boundary
311+
- boundaryDimensions.top + (boundaryDimensions.scroll.top ?? 0)// this is the top of the boundary
312312
- ((margins.top ?? 0) + (margins.bottom ?? 0) + padding) // save additional space for margin and padding
313313
);
314314
return Math.min(boundaryDimensions.height - (padding * 2), maxHeight);
@@ -320,13 +320,15 @@ function getAvailableSpace(
320320
childOffset: Offset, // trigger
321321
margins: Position, // overlay
322322
padding: number, // overlay <-> boundary
323-
placementInfo: ParsedPlacement
323+
placementInfo: ParsedPlacement,
324+
shouldAccountForScroll: boolean
324325
) {
325326
let {placement, axis, size} = placementInfo;
326327
if (placement === axis) {
327328
return Math.max(0,
328329
childOffset[axis] // trigger start
329330
- boundaryDimensions[axis] // boundary start
331+
- (shouldAccountForScroll ? (boundaryDimensions.scroll[axis]) ?? 0 + containerOffsetWithBoundary[axis] : 0)
330332
- (margins[axis] ?? 0) // margins usually for arrows or other decorations
331333
- margins[FLIPPED_DIRECTION[axis]]
332334
- padding); // padding between overlay and boundary
@@ -335,11 +337,12 @@ function getAvailableSpace(
335337
return Math.max(0,
336338
boundaryDimensions[size]
337339
+ boundaryDimensions[axis]
338-
- childOffset[axis]
339-
- childOffset[size]
340-
- (margins[axis] ?? 0)
341-
- margins[FLIPPED_DIRECTION[axis]]
342-
- padding);
340+
+ (shouldAccountForScroll ? (boundaryDimensions.scroll[axis] ?? 0 + containerOffsetWithBoundary[axis]) : 0)
341+
- childOffset[axis]
342+
- childOffset[size]
343+
- (margins[axis] ?? 0)
344+
- margins[FLIPPED_DIRECTION[axis]]
345+
- padding);
343346
}
344347

345348
export function calculatePositionInternal(
@@ -358,7 +361,8 @@ export function calculatePositionInternal(
358361
isContainerPositioned: boolean,
359362
userSetMaxHeight: number | undefined,
360363
arrowSize: number,
361-
arrowBoundaryOffset: number
364+
arrowBoundaryOffset: number,
365+
shouldAccountForScroll: boolean
362366
): PositionResult {
363367
let placementInfo = parsePlacement(placementInput);
364368
let {size, crossAxis, crossSize, placement, crossPlacement} = placementInfo;
@@ -370,7 +374,8 @@ export function calculatePositionInternal(
370374
childOffset,
371375
margins,
372376
padding + offset,
373-
placementInfo
377+
placementInfo,
378+
shouldAccountForScroll
374379
);
375380

376381
// Check if the scroll size of the overlay is greater than the available space to determine if we need to flip
@@ -384,7 +389,8 @@ export function calculatePositionInternal(
384389
childOffset,
385390
margins,
386391
padding + offset,
387-
flippedPlacementInfo
392+
flippedPlacementInfo,
393+
shouldAccountForScroll
388394
);
389395

390396
// If the available space for the flipped position is greater than the original available space, flip.
@@ -530,12 +536,9 @@ export function calculatePosition(opts: PositionOpts): PositionResult {
530536
// If the container is the HTML element wrapping the body element, the retrieved scrollTop/scrollLeft will be equal to the
531537
// 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
532538
// 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);
534-
if (container.tagName === 'HTML' && boundaryElement.tagName === 'BODY') {
535-
containerDimensions.scroll.top = 0;
536-
containerDimensions.scroll.left = 0;
537-
}
539+
let containerOffsetWithBoundary: Offset = getPosition(boundaryElement, container, false);
538540

541+
let shouldAccountForScroll = !isViewportContainer || boundaryElement === document.body;
539542
return calculatePositionInternal(
540543
placement,
541544
childOffset,
@@ -552,7 +555,8 @@ export function calculatePosition(opts: PositionOpts): PositionResult {
552555
isContainerPositioned,
553556
maxHeight,
554557
arrowSize,
555-
arrowBoundaryOffset
558+
arrowBoundaryOffset,
559+
shouldAccountForScroll
556560
);
557561
}
558562

0 commit comments

Comments
 (0)