in src/cdk/overlay/position/flexible-connected-position-strategy.ts [759:830]
private _calculateBoundingBoxRect(origin: Point, position: ConnectedPosition): BoundingBoxRect {
const viewport = this._viewportRect;
const isRtl = this._isRtl();
let height: number, top: number, bottom: number;
if (position.overlayY === 'top') {
// Overlay is opening "downward" and thus is bound by the bottom viewport edge.
top = origin.y;
height = viewport.height - top + this._viewportMargin;
} else if (position.overlayY === 'bottom') {
// Overlay is opening "upward" and thus is bound by the top viewport edge. We need to add
// the viewport margin back in, because the viewport rect is narrowed down to remove the
// margin, whereas the `origin` position is calculated based on its `ClientRect`.
bottom = viewport.height - origin.y + this._viewportMargin * 2;
height = viewport.height - bottom + this._viewportMargin;
} else {
// If neither top nor bottom, it means that the overlay is vertically centered on the
// origin point. Note that we want the position relative to the viewport, rather than
// the page, which is why we don't use something like `viewport.bottom - origin.y` and
// `origin.y - viewport.top`.
const smallestDistanceToViewportEdge = Math.min(
viewport.bottom - origin.y + viewport.top,
origin.y,
);
const previousHeight = this._lastBoundingBoxSize.height;
height = smallestDistanceToViewportEdge * 2;
top = origin.y - smallestDistanceToViewportEdge;
if (height > previousHeight && !this._isInitialRender && !this._growAfterOpen) {
top = origin.y - previousHeight / 2;
}
}
// The overlay is opening 'right-ward' (the content flows to the right).
const isBoundedByRightViewportEdge =
(position.overlayX === 'start' && !isRtl) || (position.overlayX === 'end' && isRtl);
// The overlay is opening 'left-ward' (the content flows to the left).
const isBoundedByLeftViewportEdge =
(position.overlayX === 'end' && !isRtl) || (position.overlayX === 'start' && isRtl);
let width: number, left: number, right: number;
if (isBoundedByLeftViewportEdge) {
right = viewport.width - origin.x + this._viewportMargin;
width = origin.x - this._viewportMargin;
} else if (isBoundedByRightViewportEdge) {
left = origin.x;
width = viewport.right - origin.x;
} else {
// If neither start nor end, it means that the overlay is horizontally centered on the
// origin point. Note that we want the position relative to the viewport, rather than
// the page, which is why we don't use something like `viewport.right - origin.x` and
// `origin.x - viewport.left`.
const smallestDistanceToViewportEdge = Math.min(
viewport.right - origin.x + viewport.left,
origin.x,
);
const previousWidth = this._lastBoundingBoxSize.width;
width = smallestDistanceToViewportEdge * 2;
left = origin.x - smallestDistanceToViewportEdge;
if (width > previousWidth && !this._isInitialRender && !this._growAfterOpen) {
left = origin.x - previousWidth / 2;
}
}
return {top: top!, left: left!, bottom: bottom!, right: right!, width, height};
}