/**
 * Recursively union the bounding rects of all element descendants of `el`
 * that have a non-zero size. Zero-size children (e.g. `display: contents`
 * wrappers such as Pega's `Inspectable`) are descended into rather than
 * skipped, so that deeply nested editable wrappers contribute their
 * children's rects to the parent's effective rect.
 *
 * Only element children are visited — bare text nodes are intentionally
 * excluded to avoid the multi-layout-column spanning issue that affected
 * the previous `Range.getBoundingClientRect` approach.
 */
const unionChildRects = (el) => {
    return [...el.children].reduce((union, child) => {
        const childRect = child.getBoundingClientRect();
        if (childRect.width !== 0 || childRect.height !== 0) {
            return {
                left: Math.min(union.left, childRect.left),
                top: Math.min(union.top, childRect.top),
                right: Math.max(union.right, childRect.right),
                bottom: Math.max(union.bottom, childRect.bottom)
            };
        }
        // Zero-size child (e.g. display:contents Inspectable wrapper) — recurse
        // so its element descendants are still included in the union.
        const nested = unionChildRects(child);
        return {
            left: Math.min(union.left, nested.left),
            top: Math.min(union.top, nested.top),
            right: Math.max(union.right, nested.right),
            bottom: Math.max(union.bottom, nested.bottom)
        };
    }, {
        left: Infinity,
        top: Infinity,
        right: -Infinity,
        bottom: -Infinity
    });
};
/**
 * Returns the visible bounding rect for an element, robust to wrappers
 * that use `display: contents`. Such wrappers have no box of their own
 * but the content they enclose still paints — `Range.getBoundingClientRect`
 * yields the union of the rendered content (including text nodes), which
 * is what we want for both Inspector highlight frames and UI Designer
 * geometry reports.
 */
const getEffectiveRect = (el) => {
    const win = el.ownerDocument?.defaultView ?? window;
    const docEl = el.ownerDocument?.documentElement;
    let { left, top, width, height } = el.getBoundingClientRect();
    // display:contents (and other no-box elements) return 0/0.
    // Union element-children rects recursively (zero-size children such as
    // display:contents Inspectable wrappers are descended into rather than
    // skipped), instead of using Range which walks ALL text descendants and
    // can span multiple layout columns.
    if (width === 0 && height === 0) {
        const union = unionChildRects(el);
        if (union.left !== Infinity) {
            left = union.left;
            top = union.top;
            width = union.right - union.left;
            height = union.bottom - union.top;
        }
    }
    // Clip to overflow-constraining ancestors.
    let right = left + width;
    let bottom = top + height;
    let ancestor = el.parentElement;
    while (ancestor && ancestor !== docEl) {
        const style = win.getComputedStyle(ancestor);
        const ox = style.overflowX;
        const oy = style.overflowY;
        const clips = ox === 'hidden' ||
            ox === 'clip' ||
            ox === 'scroll' ||
            ox === 'auto' ||
            oy === 'hidden' ||
            oy === 'clip' ||
            oy === 'scroll' ||
            oy === 'auto';
        if (clips) {
            const ar = ancestor.getBoundingClientRect();
            left = Math.max(left, ar.left);
            top = Math.max(top, ar.top);
            right = Math.min(right, ar.right);
            bottom = Math.min(bottom, ar.bottom);
        }
        ancestor = ancestor.parentElement;
    }
    return { left, top, width: Math.max(0, right - left), height: Math.max(0, bottom - top) };
};
export default getEffectiveRect;
//# sourceMappingURL=getEffectiveRect.js.map