export function recalcPositionFromLayoutData()

in src/common/PopupContainerViewBase.tsx [56:235]


export function recalcPositionFromLayoutData(windowDims: Dimensions, anchorRect: ClientRect, popupRect: Dimensions,
        positionPriorities?: PopupPosition[], useInnerPositioning?: boolean): RecalcResult | undefined {
    // If the anchor has disappeared, dismiss the popup.
    if (!(anchorRect.width > 0 && anchorRect.height > 0)) {
        return undefined;
    }

    // If the anchor is no longer in the window's bounds, cancel the popup.
    if (anchorRect.left >= windowDims.width || anchorRect.right <= 0 ||
            anchorRect.bottom <= 0 || anchorRect.top >= windowDims.height) {
        return undefined;
    }

    let positionsToTry = positionPriorities;
    if (!positionsToTry || positionsToTry.length === 0) {
        positionsToTry = ['bottom', 'right', 'top', 'left'];
    }
    if (positionsToTry.length === 1 && positionsToTry[0] === 'context') {
        // Context only works with exact matches, so fall back to walking around the compass if it doesn't fit exactly.
        positionsToTry.push('bottom', 'right', 'top', 'left');
    }

    if (useInnerPositioning) {
        // If the popup is meant to be shown inside the anchor we need to recalculate
        // the position differently.
        return recalcInnerPosition(anchorRect, positionsToTry[0], popupRect.width, popupRect.height);
    }

    // Start by assuming that we'll be unconstrained.
    const result: RecalcResult = {
        popupX: 0,
        popupY: 0,
        anchorOffset: 0,
        anchorPosition: 'top',
        constrainedPopupWidth: popupRect.width,
        constrainedPopupHeight: popupRect.height,
    };

    let foundPerfectFit = false;
    let foundPartialFit = false;

    positionsToTry.forEach(pos => {
        if (!foundPerfectFit) {
            let absX = 0;
            let absY = 0;
            let anchorOffset = 0;
            let constrainedWidth = 0;
            let constrainedHeight = 0;

            switch (pos) {
                case 'bottom':
                    absY = anchorRect.bottom;
                    absX = anchorRect.left + (anchorRect.width - popupRect.width) / 2;
                    anchorOffset = popupRect.width / 2;

                    if (popupRect.height <= windowDims.height - ALLEY_WIDTH - anchorRect.bottom) {
                        foundPerfectFit = true;
                    } else if (!foundPartialFit) {
                        constrainedHeight = windowDims.height - ALLEY_WIDTH - anchorRect.bottom;
                    }
                    break;

                case 'top':
                    absY = anchorRect.top - popupRect.height;
                    absX = anchorRect.left + (anchorRect.width - popupRect.width) / 2;
                    anchorOffset = popupRect.width / 2;

                    if (popupRect.height <= anchorRect.top - ALLEY_WIDTH) {
                        foundPerfectFit = true;
                    } else if (!foundPartialFit) {
                        constrainedHeight = anchorRect.top - ALLEY_WIDTH;
                    }
                    break;

                case 'right':
                    absX = anchorRect.right;
                    absY = anchorRect.top + (anchorRect.height - popupRect.height) / 2;
                    anchorOffset = popupRect.height / 2;

                    if (popupRect.width <= windowDims.width - ALLEY_WIDTH - anchorRect.right) {
                        foundPerfectFit = true;
                    } else if (!foundPartialFit) {
                        constrainedWidth = windowDims.width - ALLEY_WIDTH - anchorRect.right;
                    }
                    break;

                case 'left':
                    absX = anchorRect.left - popupRect.width;
                    absY = anchorRect.top + (anchorRect.height - popupRect.height) / 2;
                    anchorOffset = popupRect.height / 2;

                    if (popupRect.width <= anchorRect.left - ALLEY_WIDTH) {
                        foundPerfectFit = true;
                    } else if (!foundPartialFit) {
                        constrainedWidth = anchorRect.left - ALLEY_WIDTH;
                    }
                    break;

                case 'context': {
                    // Search for perfect fits on the LR, LL, TR, and TL corners.
                    const fitsAbove = anchorRect.top - popupRect.height >= ALLEY_WIDTH;
                    const fitsBelow = anchorRect.top + anchorRect.height + popupRect.height <= windowDims.height - ALLEY_WIDTH;
                    const fitsLeft = anchorRect.left - popupRect.width >= ALLEY_WIDTH;
                    const fitsRight = anchorRect.left + anchorRect.width + popupRect.width <= windowDims.width - ALLEY_WIDTH;
                    if (fitsBelow && fitsRight) {
                        foundPerfectFit = true;
                        absX = anchorRect.left + anchorRect.width;
                        absY = anchorRect.top + anchorRect.height;
                    } else if (fitsBelow && fitsLeft) {
                        foundPerfectFit = true;
                        absX = anchorRect.left - popupRect.width;
                        absY = anchorRect.top + anchorRect.height;
                    } else if (fitsAbove && fitsRight) {
                        foundPerfectFit = true;
                        absX = anchorRect.left + anchorRect.width;
                        absY = anchorRect.top - popupRect.height;
                    } else if (fitsAbove && fitsLeft) {
                        foundPerfectFit = true;
                        absX = anchorRect.left - popupRect.width;
                        absY = anchorRect.top - popupRect.height;
                    }
                    break;
                }
            }

            const effectiveWidth = constrainedWidth || popupRect.width;
            const effectiveHeight = constrainedHeight || popupRect.height;

            // Make sure we're not hanging off the bounds of the window.
            if (absX < ALLEY_WIDTH) {
                if (pos === 'top' || pos === 'bottom') {
                    anchorOffset -= ALLEY_WIDTH - absX;
                    if (anchorOffset < MIN_ANCHOR_OFFSET || anchorOffset > effectiveWidth - MIN_ANCHOR_OFFSET) {
                        foundPerfectFit = false;
                    }
                }
                absX = ALLEY_WIDTH;
            } else if (absX > windowDims.width - ALLEY_WIDTH - effectiveWidth) {
                if (pos === 'top' || pos === 'bottom') {
                    anchorOffset -= (windowDims.width - ALLEY_WIDTH - effectiveWidth - absX);
                    if (anchorOffset < MIN_ANCHOR_OFFSET || anchorOffset > effectiveWidth - MIN_ANCHOR_OFFSET) {
                        foundPerfectFit = false;
                    }
                }
                absX = windowDims.width - ALLEY_WIDTH - effectiveWidth;
            }

            if (absY < ALLEY_WIDTH) {
                if (pos === 'right' || pos === 'left') {
                    anchorOffset += absY - ALLEY_WIDTH;
                    if (anchorOffset < MIN_ANCHOR_OFFSET || anchorOffset > effectiveHeight - MIN_ANCHOR_OFFSET) {
                        foundPerfectFit = false;
                    }
                }
                absY = ALLEY_WIDTH;
            } else if (absY > windowDims.height - ALLEY_WIDTH - effectiveHeight) {
                if (pos === 'right' || pos === 'left') {
                    anchorOffset -= (windowDims.height - ALLEY_WIDTH - effectiveHeight - absY);
                    if (anchorOffset < MIN_ANCHOR_OFFSET || anchorOffset > effectiveHeight - MIN_ANCHOR_OFFSET) {
                        foundPerfectFit = false;
                    }
                }
                absY = windowDims.height - ALLEY_WIDTH - effectiveHeight;
            }

            if (foundPerfectFit || effectiveHeight > 0 || effectiveWidth > 0) {
                result.popupY = absY;
                result.popupX = absX;
                result.anchorOffset = anchorOffset;
                result.anchorPosition = pos;
                result.constrainedPopupWidth = effectiveWidth;
                result.constrainedPopupHeight = effectiveHeight;

                foundPartialFit = true;
            }
        }
    });

    return result;
}