Skip to content

Commit 0d96e0d

Browse files
authored
chore: Revert overlay positioning changes (#8847)
Will undo this in next PR built off this one
1 parent 53366f0 commit 0d96e0d

File tree

3 files changed

+33
-59
lines changed

3 files changed

+33
-59
lines changed

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

Lines changed: 29 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -110,11 +110,7 @@ function getContainerDimensions(containerNode: Element): Dimensions {
110110
let scroll: Position = {};
111111
let isPinchZoomedIn = (visualViewport?.scale ?? 1) > 1;
112112

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') {
118114
let documentElement = document.documentElement;
119115
totalWidth = documentElement.clientWidth;
120116
totalHeight = documentElement.clientHeight;
@@ -183,13 +179,10 @@ function getDelta(
183179
let boundarySize = boundaryDimensions[AXIS_SIZE[axis]];
184180
// Calculate the edges of the boundary (accomodating for the boundary padding) and the edges of the overlay.
185181
// 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]];
193186

194187
// If any of the overlay edges falls outside of the boundary, shift the overlay the required amount to align one of the overlay's
195188
// edges with the closest boundary edge.
@@ -241,8 +234,7 @@ function computePosition(
241234
containerOffsetWithBoundary: Offset,
242235
isContainerPositioned: boolean,
243236
arrowSize: number,
244-
arrowBoundaryOffset: number,
245-
containerDimensions: Dimensions
237+
arrowBoundaryOffset: number
246238
) {
247239
let {placement, crossPlacement, axis, crossAxis, size, crossSize} = placementInfo;
248240
let position: Position = {};
@@ -263,9 +255,9 @@ function computePosition(
263255

264256
position[crossAxis]! += crossOffset;
265257

266-
// overlay top or left overlapping arrow with button bottom or right
258+
// overlay top overlapping arrow with button bottom
267259
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
269261
const maxPosition = childOffset[crossAxis] + childOffset[crossSize] - arrowSize - arrowBoundaryOffset;
270262
position[crossAxis] = clamp(position[crossAxis]!, minPosition, maxPosition);
271263

@@ -274,8 +266,8 @@ function computePosition(
274266
// If the container is positioned (non-static), then we use the container's actual
275267
// height, as `bottom` will be relative to this height. But if the container is static,
276268
// 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]]);
279271
position[FLIPPED_DIRECTION[axis]] = Math.floor(containerHeight - childOffset[axis] + offset);
280272
} else {
281273
position[axis] = Math.floor(childOffset[axis] + childOffset[size] + offset);
@@ -291,55 +283,42 @@ function getMaxHeight(
291283
margins: Position,
292284
padding: number,
293285
overlayHeight: number,
294-
heightGrowthDirection: HeightGrowthDirection,
295-
containerDimensions: Dimensions
286+
heightGrowthDirection: HeightGrowthDirection
296287
) {
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);
301292
let maxHeight = heightGrowthDirection !== 'top' ?
302293
// We want the distance between the top of the overlay to the bottom of the boundary
303294
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
305296
- overlayTop // this is the top of the overlay
306297
- ((margins.top ?? 0) + (margins.bottom ?? 0) + padding) // save additional space for margin and padding
307298
)
308299
// We want the distance between the bottom of the overlay to the top of the boundary
309300
: Math.max(0,
310301
(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
312303
- ((margins.top ?? 0) + (margins.bottom ?? 0) + padding) // save additional space for margin and padding
313304
);
314305
return Math.min(boundaryDimensions.height - (padding * 2), maxHeight);
315306
}
316307

317308
function getAvailableSpace(
318-
boundaryDimensions: Dimensions, // boundary
309+
boundaryDimensions: Dimensions,
319310
containerOffsetWithBoundary: Offset,
320-
childOffset: Offset, // trigger
321-
margins: Position, // overlay
322-
padding: number, // overlay <-> boundary
311+
childOffset: Offset,
312+
margins: Position,
313+
padding: number,
323314
placementInfo: ParsedPlacement
324315
) {
325316
let {placement, axis, size} = placementInfo;
326317
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);
333319
}
334320

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);
343322
}
344323

345324
export function calculatePositionInternal(
@@ -362,7 +341,7 @@ export function calculatePositionInternal(
362341
): PositionResult {
363342
let placementInfo = parsePlacement(placementInput);
364343
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);
366345
let normalizedOffset = offset;
367346
let space = getAvailableSpace(
368347
boundaryDimensions,
@@ -376,8 +355,7 @@ export function calculatePositionInternal(
376355
// Check if the scroll size of the overlay is greater than the available space to determine if we need to flip
377356
if (flip && scrollSize[size] > space) {
378357
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);
381359
let flippedSpace = getAvailableSpace(
382360
boundaryDimensions,
383361
containerOffsetWithBoundary,
@@ -422,8 +400,7 @@ export function calculatePositionInternal(
422400
margins,
423401
padding,
424402
overlaySize.height,
425-
heightGrowthDirection,
426-
containerDimensions
403+
heightGrowthDirection
427404
);
428405

429406
if (userSetMaxHeight && userSetMaxHeight < maxHeight) {
@@ -432,7 +409,7 @@ export function calculatePositionInternal(
432409

433410
overlaySize.height = Math.min(overlaySize.height, maxHeight);
434411

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);
436413
delta = getDelta(crossAxis, position[crossAxis]!, overlaySize[crossSize], boundaryDimensions, containerDimensions, padding, containerOffsetWithBoundary);
437414
position[crossAxis]! += delta;
438415

@@ -530,7 +507,7 @@ export function calculatePosition(opts: PositionOpts): PositionResult {
530507
// If the container is the HTML element wrapping the body element, the retrieved scrollTop/scrollLeft will be equal to the
531508
// 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
532509
// 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);
534511
if (container.tagName === 'HTML' && boundaryElement.tagName === 'BODY') {
535512
containerDimensions.scroll.top = 0;
536513
containerDimensions.scroll.left = 0;
@@ -559,7 +536,7 @@ export function calculatePosition(opts: PositionOpts): PositionResult {
559536
export function getRect(node: Element, ignoreScale: boolean) {
560537
let {top, left, width, height} = node.getBoundingClientRect();
561538

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
563540
// the size is not affected by scale transforms.
564541
if (ignoreScale && node instanceof node.ownerDocument.defaultView!.HTMLElement) {
565542
width = node.offsetWidth;

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

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,16 +138,13 @@ describe('calculatePosition', function () {
138138
};
139139

140140
const container = createElementWithDimensions('div', containerDimensions);
141-
Object.assign(container.style, {
142-
position: 'relative'
143-
});
144141
const target = createElementWithDimensions('div', targetDimension);
145142
const overlay = createElementWithDimensions('div', overlaySize, margins);
146143

147144
const parentElement = document.createElement('div');
148145
parentElement.appendChild(container);
149146
parentElement.appendChild(target);
150-
container.appendChild(overlay);
147+
parentElement.appendChild(overlay);
151148

152149
document.documentElement.appendChild(parentElement);
153150

packages/@react-aria/overlays/test/useOverlayPosition.test.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ describe('useOverlayPosition', function () {
8989
position: absolute;
9090
z-index: 100000;
9191
left: 12px;
92-
bottom: 350px;
92+
bottom: 518px;
9393
max-height: 238px;
9494
`);
9595

@@ -281,7 +281,7 @@ describe('useOverlayPosition with positioned container', () => {
281281
z-index: 100000;
282282
left: 12px;
283283
top: 200px;
284-
max-height: 556px;
284+
max-height: 406px;
285285
`);
286286

287287
expect(overlay).toHaveTextContent('placement: bottom');
@@ -303,7 +303,7 @@ describe('useOverlayPosition with positioned container', () => {
303303
z-index: 100000;
304304
left: 12px;
305305
bottom: 300px;
306-
max-height: 88px;
306+
max-height: 238px;
307307
`);
308308

309309
expect(overlay).toHaveTextContent('placement: top');

0 commit comments

Comments
 (0)