@react-aria/overlays
Version:
Spectrum UI components in React
366 lines (362 loc) • 28.3 kB
JavaScript
import {isWebKit as $fZVmS$isWebKit, clamp as $fZVmS$clamp} from "@react-aria/utils";
/*
* Copyright 2020 Adobe. All rights reserved.
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
const $edcf132a9284368a$var$AXIS = {
top: 'top',
bottom: 'top',
left: 'left',
right: 'left'
};
const $edcf132a9284368a$var$FLIPPED_DIRECTION = {
top: 'bottom',
bottom: 'top',
left: 'right',
right: 'left'
};
const $edcf132a9284368a$var$CROSS_AXIS = {
top: 'left',
left: 'top'
};
const $edcf132a9284368a$var$AXIS_SIZE = {
top: 'height',
left: 'width'
};
const $edcf132a9284368a$var$TOTAL_SIZE = {
width: 'totalWidth',
height: 'totalHeight'
};
const $edcf132a9284368a$var$PARSED_PLACEMENT_CACHE = {};
let $edcf132a9284368a$var$visualViewport = typeof document !== 'undefined' ? window.visualViewport : null;
function $edcf132a9284368a$var$getContainerDimensions(containerNode) {
let width = 0, height = 0, totalWidth = 0, totalHeight = 0, top = 0, left = 0;
let scroll = {};
var _visualViewport_scale;
let isPinchZoomedIn = ((_visualViewport_scale = $edcf132a9284368a$var$visualViewport === null || $edcf132a9284368a$var$visualViewport === void 0 ? void 0 : $edcf132a9284368a$var$visualViewport.scale) !== null && _visualViewport_scale !== void 0 ? _visualViewport_scale : 1) > 1;
if (containerNode.tagName === 'BODY') {
let documentElement = document.documentElement;
totalWidth = documentElement.clientWidth;
totalHeight = documentElement.clientHeight;
var _visualViewport_width;
width = (_visualViewport_width = $edcf132a9284368a$var$visualViewport === null || $edcf132a9284368a$var$visualViewport === void 0 ? void 0 : $edcf132a9284368a$var$visualViewport.width) !== null && _visualViewport_width !== void 0 ? _visualViewport_width : totalWidth;
var _visualViewport_height;
height = (_visualViewport_height = $edcf132a9284368a$var$visualViewport === null || $edcf132a9284368a$var$visualViewport === void 0 ? void 0 : $edcf132a9284368a$var$visualViewport.height) !== null && _visualViewport_height !== void 0 ? _visualViewport_height : totalHeight;
scroll.top = documentElement.scrollTop || containerNode.scrollTop;
scroll.left = documentElement.scrollLeft || containerNode.scrollLeft;
// The goal of the below is to get a top/left value that represents the top/left of the visual viewport with
// respect to the layout viewport origin. This combined with the scrollTop/scrollLeft will allow us to calculate
// coordinates/values with respect to the visual viewport or with respect to the layout viewport.
if ($edcf132a9284368a$var$visualViewport) {
top = $edcf132a9284368a$var$visualViewport.offsetTop;
left = $edcf132a9284368a$var$visualViewport.offsetLeft;
}
} else {
({ width: width, height: height, top: top, left: left } = $edcf132a9284368a$var$getOffset(containerNode));
scroll.top = containerNode.scrollTop;
scroll.left = containerNode.scrollLeft;
totalWidth = width;
totalHeight = height;
}
if ((0, $fZVmS$isWebKit)() && (containerNode.tagName === 'BODY' || containerNode.tagName === 'HTML') && isPinchZoomedIn) {
// Safari will report a non-zero scrollTop/Left for the non-scrolling body/HTML element when pinch zoomed in unlike other browsers.
// Set to zero for parity calculations so we get consistent positioning of overlays across all browsers.
// Also switch to visualViewport.pageTop/pageLeft so that we still accomodate for scroll positioning for body/HTML elements that are actually scrollable
// before pinch zoom happens
scroll.top = 0;
scroll.left = 0;
var _visualViewport_pageTop;
top = (_visualViewport_pageTop = $edcf132a9284368a$var$visualViewport === null || $edcf132a9284368a$var$visualViewport === void 0 ? void 0 : $edcf132a9284368a$var$visualViewport.pageTop) !== null && _visualViewport_pageTop !== void 0 ? _visualViewport_pageTop : 0;
var _visualViewport_pageLeft;
left = (_visualViewport_pageLeft = $edcf132a9284368a$var$visualViewport === null || $edcf132a9284368a$var$visualViewport === void 0 ? void 0 : $edcf132a9284368a$var$visualViewport.pageLeft) !== null && _visualViewport_pageLeft !== void 0 ? _visualViewport_pageLeft : 0;
}
return {
width: width,
height: height,
totalWidth: totalWidth,
totalHeight: totalHeight,
scroll: scroll,
top: top,
left: left
};
}
function $edcf132a9284368a$var$getScroll(node) {
return {
top: node.scrollTop,
left: node.scrollLeft,
width: node.scrollWidth,
height: node.scrollHeight
};
}
// Determines the amount of space required when moving the overlay to ensure it remains in the boundary
function $edcf132a9284368a$var$getDelta(axis, offset, size, // The dimensions of the boundary element that the popover is
// positioned within (most of the time this is the <body>).
boundaryDimensions, // The dimensions of the containing block element that the popover is
// positioned relative to (e.g. parent with position: relative).
// Usually this is the same as the boundary element, but if the popover
// is portaled somewhere other than the body and has an ancestor with
// position: relative/absolute, it will be different.
containerDimensions, padding, containerOffsetWithBoundary) {
var _containerDimensions_scroll_axis;
let containerScroll = (_containerDimensions_scroll_axis = containerDimensions.scroll[axis]) !== null && _containerDimensions_scroll_axis !== void 0 ? _containerDimensions_scroll_axis : 0;
// The height/width of the boundary. Matches the axis along which we are adjusting the overlay position
let boundarySize = boundaryDimensions[$edcf132a9284368a$var$AXIS_SIZE[axis]];
// Calculate the edges of the boundary (accomodating for the boundary padding) and the edges of the overlay.
// Note that these values are with respect to the visual viewport (aka 0,0 is the top left of the viewport)
let boundaryStartEdge = boundaryDimensions.scroll[$edcf132a9284368a$var$AXIS[axis]] + padding;
let boundaryEndEdge = boundarySize + boundaryDimensions.scroll[$edcf132a9284368a$var$AXIS[axis]] - padding;
let startEdgeOffset = offset - containerScroll + containerOffsetWithBoundary[axis] - boundaryDimensions[$edcf132a9284368a$var$AXIS[axis]];
let endEdgeOffset = offset - containerScroll + size + containerOffsetWithBoundary[axis] - boundaryDimensions[$edcf132a9284368a$var$AXIS[axis]];
// If any of the overlay edges falls outside of the boundary, shift the overlay the required amount to align one of the overlay's
// edges with the closest boundary edge.
if (startEdgeOffset < boundaryStartEdge) return boundaryStartEdge - startEdgeOffset;
else if (endEdgeOffset > boundaryEndEdge) return Math.max(boundaryEndEdge - endEdgeOffset, boundaryStartEdge - startEdgeOffset);
else return 0;
}
function $edcf132a9284368a$var$getMargins(node) {
let style = window.getComputedStyle(node);
return {
top: parseInt(style.marginTop, 10) || 0,
bottom: parseInt(style.marginBottom, 10) || 0,
left: parseInt(style.marginLeft, 10) || 0,
right: parseInt(style.marginRight, 10) || 0
};
}
function $edcf132a9284368a$var$parsePlacement(input) {
if ($edcf132a9284368a$var$PARSED_PLACEMENT_CACHE[input]) return $edcf132a9284368a$var$PARSED_PLACEMENT_CACHE[input];
let [placement, crossPlacement] = input.split(' ');
let axis = $edcf132a9284368a$var$AXIS[placement] || 'right';
let crossAxis = $edcf132a9284368a$var$CROSS_AXIS[axis];
if (!$edcf132a9284368a$var$AXIS[crossPlacement]) crossPlacement = 'center';
let size = $edcf132a9284368a$var$AXIS_SIZE[axis];
let crossSize = $edcf132a9284368a$var$AXIS_SIZE[crossAxis];
$edcf132a9284368a$var$PARSED_PLACEMENT_CACHE[input] = {
placement: placement,
crossPlacement: crossPlacement,
axis: axis,
crossAxis: crossAxis,
size: size,
crossSize: crossSize
};
return $edcf132a9284368a$var$PARSED_PLACEMENT_CACHE[input];
}
function $edcf132a9284368a$var$computePosition(childOffset, boundaryDimensions, overlaySize, placementInfo, offset, crossOffset, containerOffsetWithBoundary, isContainerPositioned, arrowSize, arrowBoundaryOffset) {
let { placement: placement, crossPlacement: crossPlacement, axis: axis, crossAxis: crossAxis, size: size, crossSize: crossSize } = placementInfo;
let position = {};
var _childOffset_crossAxis;
// button position
position[crossAxis] = (_childOffset_crossAxis = childOffset[crossAxis]) !== null && _childOffset_crossAxis !== void 0 ? _childOffset_crossAxis : 0;
var _childOffset_crossSize, _overlaySize_crossSize, _childOffset_crossSize1, _overlaySize_crossSize1;
if (crossPlacement === 'center') // + (button size / 2) - (overlay size / 2)
// at this point the overlay center should match the button center
position[crossAxis] += (((_childOffset_crossSize = childOffset[crossSize]) !== null && _childOffset_crossSize !== void 0 ? _childOffset_crossSize : 0) - ((_overlaySize_crossSize = overlaySize[crossSize]) !== null && _overlaySize_crossSize !== void 0 ? _overlaySize_crossSize : 0)) / 2;
else if (crossPlacement !== crossAxis) // + (button size) - (overlay size)
// at this point the overlay bottom should match the button bottom
position[crossAxis] += ((_childOffset_crossSize1 = childOffset[crossSize]) !== null && _childOffset_crossSize1 !== void 0 ? _childOffset_crossSize1 : 0) - ((_overlaySize_crossSize1 = overlaySize[crossSize]) !== null && _overlaySize_crossSize1 !== void 0 ? _overlaySize_crossSize1 : 0);
/* else {
the overlay top should match the button top
} */
position[crossAxis] += crossOffset;
// overlay top overlapping arrow with button bottom
const minPosition = childOffset[crossAxis] - overlaySize[crossSize] + arrowSize + arrowBoundaryOffset;
// overlay bottom overlapping arrow with button top
const maxPosition = childOffset[crossAxis] + childOffset[crossSize] - arrowSize - arrowBoundaryOffset;
position[crossAxis] = (0, $fZVmS$clamp)(position[crossAxis], minPosition, maxPosition);
// Floor these so the position isn't placed on a partial pixel, only whole pixels. Shouldn't matter if it was floored or ceiled, so chose one.
if (placement === axis) {
// If the container is positioned (non-static), then we use the container's actual
// height, as `bottom` will be relative to this height. But if the container is static,
// then it can only be the `document.body`, and `bottom` will be relative to _its_
// container, which should be as large as boundaryDimensions.
const containerHeight = isContainerPositioned ? containerOffsetWithBoundary[size] : boundaryDimensions[$edcf132a9284368a$var$TOTAL_SIZE[size]];
position[$edcf132a9284368a$var$FLIPPED_DIRECTION[axis]] = Math.floor(containerHeight - childOffset[axis] + offset);
} else position[axis] = Math.floor(childOffset[axis] + childOffset[size] + offset);
return position;
}
function $edcf132a9284368a$var$getMaxHeight(position, boundaryDimensions, containerOffsetWithBoundary, isContainerPositioned, margins, padding, overlayHeight, heightGrowthDirection) {
const containerHeight = isContainerPositioned ? containerOffsetWithBoundary.height : boundaryDimensions[$edcf132a9284368a$var$TOTAL_SIZE.height];
var _position_bottom;
// 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
// used in computePosition.
let overlayTop = position.top != null ? containerOffsetWithBoundary.top + position.top : containerOffsetWithBoundary.top + (containerHeight - ((_position_bottom = position.bottom) !== null && _position_bottom !== void 0 ? _position_bottom : 0) - overlayHeight);
var _boundaryDimensions_scroll_top, _margins_top, _margins_bottom, _boundaryDimensions_scroll_top1, _margins_top1, _margins_bottom1;
let maxHeight = heightGrowthDirection !== 'top' ? // We want the distance between the top of the overlay to the bottom of the boundary
Math.max(0, boundaryDimensions.height + boundaryDimensions.top + ((_boundaryDimensions_scroll_top = boundaryDimensions.scroll.top) !== null && _boundaryDimensions_scroll_top !== void 0 ? _boundaryDimensions_scroll_top : 0) - overlayTop // this is the top of the overlay
- (((_margins_top = margins.top) !== null && _margins_top !== void 0 ? _margins_top : 0) + ((_margins_bottom = margins.bottom) !== null && _margins_bottom !== void 0 ? _margins_bottom : 0) + padding // save additional space for margin and padding
)) : Math.max(0, overlayTop + overlayHeight // this is the bottom of the overlay
- (boundaryDimensions.top + ((_boundaryDimensions_scroll_top1 = boundaryDimensions.scroll.top) !== null && _boundaryDimensions_scroll_top1 !== void 0 ? _boundaryDimensions_scroll_top1 : 0) // this is the top of the boundary
) - (((_margins_top1 = margins.top) !== null && _margins_top1 !== void 0 ? _margins_top1 : 0) + ((_margins_bottom1 = margins.bottom) !== null && _margins_bottom1 !== void 0 ? _margins_bottom1 : 0) + padding // save additional space for margin and padding
));
return Math.min(boundaryDimensions.height - padding * 2, maxHeight);
}
function $edcf132a9284368a$var$getAvailableSpace(boundaryDimensions, containerOffsetWithBoundary, childOffset, margins, padding, placementInfo) {
let { placement: placement, axis: axis, size: size } = placementInfo;
var _boundaryDimensions_scroll_axis, _margins_axis;
if (placement === axis) return Math.max(0, childOffset[axis] - boundaryDimensions[axis] - ((_boundaryDimensions_scroll_axis = boundaryDimensions.scroll[axis]) !== null && _boundaryDimensions_scroll_axis !== void 0 ? _boundaryDimensions_scroll_axis : 0) + containerOffsetWithBoundary[axis] - ((_margins_axis = margins[axis]) !== null && _margins_axis !== void 0 ? _margins_axis : 0) - margins[$edcf132a9284368a$var$FLIPPED_DIRECTION[axis]] - padding);
var _margins_axis1;
return Math.max(0, boundaryDimensions[size] + boundaryDimensions[axis] + boundaryDimensions.scroll[axis] - containerOffsetWithBoundary[axis] - childOffset[axis] - childOffset[size] - ((_margins_axis1 = margins[axis]) !== null && _margins_axis1 !== void 0 ? _margins_axis1 : 0) - margins[$edcf132a9284368a$var$FLIPPED_DIRECTION[axis]] - padding);
}
function $edcf132a9284368a$export$6839422d1f33cee9(placementInput, childOffset, overlaySize, scrollSize, margins, padding, flip, boundaryDimensions, containerDimensions, containerOffsetWithBoundary, offset, crossOffset, isContainerPositioned, userSetMaxHeight, arrowSize, arrowBoundaryOffset) {
let placementInfo = $edcf132a9284368a$var$parsePlacement(placementInput);
let { size: size, crossAxis: crossAxis, crossSize: crossSize, placement: placement, crossPlacement: crossPlacement } = placementInfo;
let position = $edcf132a9284368a$var$computePosition(childOffset, boundaryDimensions, overlaySize, placementInfo, offset, crossOffset, containerOffsetWithBoundary, isContainerPositioned, arrowSize, arrowBoundaryOffset);
let normalizedOffset = offset;
let space = $edcf132a9284368a$var$getAvailableSpace(boundaryDimensions, containerOffsetWithBoundary, childOffset, margins, padding + offset, placementInfo);
// Check if the scroll size of the overlay is greater than the available space to determine if we need to flip
if (flip && scrollSize[size] > space) {
let flippedPlacementInfo = $edcf132a9284368a$var$parsePlacement(`${$edcf132a9284368a$var$FLIPPED_DIRECTION[placement]} ${crossPlacement}`);
let flippedPosition = $edcf132a9284368a$var$computePosition(childOffset, boundaryDimensions, overlaySize, flippedPlacementInfo, offset, crossOffset, containerOffsetWithBoundary, isContainerPositioned, arrowSize, arrowBoundaryOffset);
let flippedSpace = $edcf132a9284368a$var$getAvailableSpace(boundaryDimensions, containerOffsetWithBoundary, childOffset, margins, padding + offset, flippedPlacementInfo);
// If the available space for the flipped position is greater than the original available space, flip.
if (flippedSpace > space) {
placementInfo = flippedPlacementInfo;
position = flippedPosition;
normalizedOffset = offset;
}
}
// Determine the direction the height of the overlay can grow so that we can choose how to calculate the max height
let heightGrowthDirection = 'bottom';
if (placementInfo.axis === 'top') {
if (placementInfo.placement === 'top') heightGrowthDirection = 'top';
else if (placementInfo.placement === 'bottom') heightGrowthDirection = 'bottom';
} else if (placementInfo.crossAxis === 'top') {
if (placementInfo.crossPlacement === 'top') heightGrowthDirection = 'bottom';
else if (placementInfo.crossPlacement === 'bottom') heightGrowthDirection = 'top';
}
let delta = $edcf132a9284368a$var$getDelta(crossAxis, position[crossAxis], overlaySize[crossSize], boundaryDimensions, containerDimensions, padding, containerOffsetWithBoundary);
position[crossAxis] += delta;
let maxHeight = $edcf132a9284368a$var$getMaxHeight(position, boundaryDimensions, containerOffsetWithBoundary, isContainerPositioned, margins, padding, overlaySize.height, heightGrowthDirection);
if (userSetMaxHeight && userSetMaxHeight < maxHeight) maxHeight = userSetMaxHeight;
overlaySize.height = Math.min(overlaySize.height, maxHeight);
position = $edcf132a9284368a$var$computePosition(childOffset, boundaryDimensions, overlaySize, placementInfo, normalizedOffset, crossOffset, containerOffsetWithBoundary, isContainerPositioned, arrowSize, arrowBoundaryOffset);
delta = $edcf132a9284368a$var$getDelta(crossAxis, position[crossAxis], overlaySize[crossSize], boundaryDimensions, containerDimensions, padding, containerOffsetWithBoundary);
position[crossAxis] += delta;
let arrowPosition = {};
// All values are transformed so that 0 is at the top/left of the overlay depending on the orientation
// Prefer the arrow being in the center of the trigger/overlay anchor element
// childOffset[crossAxis] + .5 * childOffset[crossSize] = absolute position with respect to the trigger's coordinate system that would place the arrow in the center of the trigger
// position[crossAxis] - margins[AXIS[crossAxis]] = value use to transform the position to a value with respect to the overlay's coordinate system. A child element's (aka arrow) position absolute's "0"
// is positioned after the margin of its parent (aka overlay) so we need to subtract it to get the proper coordinate transform
let preferredArrowPosition = childOffset[crossAxis] + .5 * childOffset[crossSize] - position[crossAxis] - margins[$edcf132a9284368a$var$AXIS[crossAxis]];
// Min/Max position limits for the arrow with respect to the overlay
const arrowMinPosition = arrowSize / 2 + arrowBoundaryOffset;
var _margins_left, _margins_right, _margins_top, _margins_bottom;
// overlaySize[crossSize] - margins = true size of the overlay
const overlayMargin = $edcf132a9284368a$var$AXIS[crossAxis] === 'left' ? ((_margins_left = margins.left) !== null && _margins_left !== void 0 ? _margins_left : 0) + ((_margins_right = margins.right) !== null && _margins_right !== void 0 ? _margins_right : 0) : ((_margins_top = margins.top) !== null && _margins_top !== void 0 ? _margins_top : 0) + ((_margins_bottom = margins.bottom) !== null && _margins_bottom !== void 0 ? _margins_bottom : 0);
const arrowMaxPosition = overlaySize[crossSize] - overlayMargin - arrowSize / 2 - arrowBoundaryOffset;
// Min/Max position limits for the arrow with respect to the trigger/overlay anchor element
// Same margin accomodation done here as well as for the preferredArrowPosition
const arrowOverlappingChildMinEdge = childOffset[crossAxis] + arrowSize / 2 - (position[crossAxis] + margins[$edcf132a9284368a$var$AXIS[crossAxis]]);
const arrowOverlappingChildMaxEdge = childOffset[crossAxis] + childOffset[crossSize] - arrowSize / 2 - (position[crossAxis] + margins[$edcf132a9284368a$var$AXIS[crossAxis]]);
// Clamp the arrow positioning so that it always is within the bounds of the anchor and the overlay
const arrowPositionOverlappingChild = (0, $fZVmS$clamp)(preferredArrowPosition, arrowOverlappingChildMinEdge, arrowOverlappingChildMaxEdge);
arrowPosition[crossAxis] = (0, $fZVmS$clamp)(arrowPositionOverlappingChild, arrowMinPosition, arrowMaxPosition);
return {
position: position,
maxHeight: maxHeight,
arrowOffsetLeft: arrowPosition.left,
arrowOffsetTop: arrowPosition.top,
placement: placementInfo.placement
};
}
function $edcf132a9284368a$export$b3ceb0cbf1056d98(opts) {
let { placement: placement, targetNode: targetNode, overlayNode: overlayNode, scrollNode: scrollNode, padding: padding, shouldFlip: shouldFlip, boundaryElement: boundaryElement, offset: offset, crossOffset: crossOffset, maxHeight: maxHeight, arrowSize: arrowSize = 0, arrowBoundaryOffset: arrowBoundaryOffset = 0 } = opts;
let container = overlayNode instanceof HTMLElement ? $edcf132a9284368a$var$getContainingBlock(overlayNode) : document.documentElement;
let isViewportContainer = container === document.documentElement;
const containerPositionStyle = window.getComputedStyle(container).position;
let isContainerPositioned = !!containerPositionStyle && containerPositionStyle !== 'static';
let childOffset = isViewportContainer ? $edcf132a9284368a$var$getOffset(targetNode) : $edcf132a9284368a$var$getPosition(targetNode, container);
if (!isViewportContainer) {
let { marginTop: marginTop, marginLeft: marginLeft } = window.getComputedStyle(targetNode);
childOffset.top += parseInt(marginTop, 10) || 0;
childOffset.left += parseInt(marginLeft, 10) || 0;
}
let overlaySize = $edcf132a9284368a$var$getOffset(overlayNode);
let margins = $edcf132a9284368a$var$getMargins(overlayNode);
var _margins_left, _margins_right;
overlaySize.width += ((_margins_left = margins.left) !== null && _margins_left !== void 0 ? _margins_left : 0) + ((_margins_right = margins.right) !== null && _margins_right !== void 0 ? _margins_right : 0);
var _margins_top, _margins_bottom;
overlaySize.height += ((_margins_top = margins.top) !== null && _margins_top !== void 0 ? _margins_top : 0) + ((_margins_bottom = margins.bottom) !== null && _margins_bottom !== void 0 ? _margins_bottom : 0);
let scrollSize = $edcf132a9284368a$var$getScroll(scrollNode);
let boundaryDimensions = $edcf132a9284368a$var$getContainerDimensions(boundaryElement);
let containerDimensions = $edcf132a9284368a$var$getContainerDimensions(container);
// If the container is the HTML element wrapping the body element, the retrieved scrollTop/scrollLeft will be equal to the
// 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
// by the container scroll since they are essentially the same containing element and thus in the same coordinate system
let containerOffsetWithBoundary = boundaryElement.tagName === 'BODY' ? $edcf132a9284368a$var$getOffset(container) : $edcf132a9284368a$var$getPosition(container, boundaryElement);
if (container.tagName === 'HTML' && boundaryElement.tagName === 'BODY') {
containerDimensions.scroll.top = 0;
containerDimensions.scroll.left = 0;
}
return $edcf132a9284368a$export$6839422d1f33cee9(placement, childOffset, overlaySize, scrollSize, margins, padding, shouldFlip, boundaryDimensions, containerDimensions, containerOffsetWithBoundary, offset, crossOffset, isContainerPositioned, maxHeight, arrowSize, arrowBoundaryOffset);
}
function $edcf132a9284368a$var$getOffset(node) {
let { top: top, left: left, width: width, height: height } = node.getBoundingClientRect();
let { scrollTop: scrollTop, scrollLeft: scrollLeft, clientTop: clientTop, clientLeft: clientLeft } = document.documentElement;
return {
top: top + scrollTop - clientTop,
left: left + scrollLeft - clientLeft,
width: width,
height: height
};
}
function $edcf132a9284368a$var$getPosition(node, parent) {
let style = window.getComputedStyle(node);
let offset;
if (style.position === 'fixed') {
let { top: top, left: left, width: width, height: height } = node.getBoundingClientRect();
offset = {
top: top,
left: left,
width: width,
height: height
};
} else {
offset = $edcf132a9284368a$var$getOffset(node);
let parentOffset = $edcf132a9284368a$var$getOffset(parent);
let parentStyle = window.getComputedStyle(parent);
parentOffset.top += (parseInt(parentStyle.borderTopWidth, 10) || 0) - parent.scrollTop;
parentOffset.left += (parseInt(parentStyle.borderLeftWidth, 10) || 0) - parent.scrollLeft;
offset.top -= parentOffset.top;
offset.left -= parentOffset.left;
}
offset.top -= parseInt(style.marginTop, 10) || 0;
offset.left -= parseInt(style.marginLeft, 10) || 0;
return offset;
}
// Returns the containing block of an element, which is the element that
// this element will be positioned relative to.
// https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block
function $edcf132a9284368a$var$getContainingBlock(node) {
// The offsetParent of an element in most cases equals the containing block.
// https://w3c.github.io/csswg-drafts/cssom-view/#dom-htmlelement-offsetparent
let offsetParent = node.offsetParent;
// The offsetParent algorithm terminates at the document body,
// even if the body is not a containing block. Double check that
// and use the documentElement if so.
if (offsetParent && offsetParent === document.body && window.getComputedStyle(offsetParent).position === 'static' && !$edcf132a9284368a$var$isContainingBlock(offsetParent)) offsetParent = document.documentElement;
// TODO(later): handle table elements?
// The offsetParent can be null if the element has position: fixed, or a few other cases.
// We have to walk up the tree manually in this case because fixed positioned elements
// are still positioned relative to their containing block, which is not always the viewport.
if (offsetParent == null) {
offsetParent = node.parentElement;
while(offsetParent && !$edcf132a9284368a$var$isContainingBlock(offsetParent))offsetParent = offsetParent.parentElement;
}
// Fall back to the viewport.
return offsetParent || document.documentElement;
}
// https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block
function $edcf132a9284368a$var$isContainingBlock(node) {
let style = window.getComputedStyle(node);
return style.transform !== 'none' || /transform|perspective/.test(style.willChange) || style.filter !== 'none' || style.contain === 'paint' || 'backdropFilter' in style && style.backdropFilter !== 'none' || 'WebkitBackdropFilter' in style && style.WebkitBackdropFilter !== 'none';
}
export {$edcf132a9284368a$export$6839422d1f33cee9 as calculatePositionInternal, $edcf132a9284368a$export$b3ceb0cbf1056d98 as calculatePosition};
//# sourceMappingURL=calculatePosition.module.js.map