"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CalloutCollisionTransform = void 0;
// Default properties which applies for dialog scenario with footer buttons
const defaultProps = {
    target: '.ms-Dialog-actions',
    container: '.ms-Dialog-main',
    absolute: true,
    minPagePadding: 10
};
const TRANSFORMATION_OFFSET = 20;
/**
 * This class is responsible for Dialog/Container element transformation to avoid collision/overlap between Callout/Dropdown Menu and target element.
 * In example when multi select dropdown is used inside dialog with actions,
 *  then class will apply transformation dialog to make sure that dialog actions and dropdown menu is visible.
 */
class CalloutCollisionTransform {
    /**
     * Initializes class with options.
     *
     * @param source Source element.
     * @param callout Dropdown menu/callout element.
     * @param props Transformation properties.
     */
    constructor(source, callout, props = defaultProps) {
        // Original style properties of container
        this.originalStyle = {};
        this.source = source;
        this.callout = callout;
        this.props = props;
        this.applyTransformation = this.applyTransformation.bind(this);
        this.resetTransformation = this.resetTransformation.bind(this);
        this.preventDismissOnEvent = this.preventDismissOnEvent.bind(this);
    }
    /**
     * Method creates placeholder element with given size.
     *
     * @param size Size of placeholder.
     * @returns HTML element for placeholder.
     */
    createPlaceholder(size) {
        const element = document.createElement('div');
        element.classList.add('ts-Callout-transformation');
        element.style.height = `${size}px`;
        return element;
    }
    /**
     * Method returns DOM elements and rectangles of associated elements(container, target, callout).
     *
     * @returns DOM elements and rectangles of associated elements.
     */
    getElements() {
        const source = this.source.current;
        const container = source?.closest(this.props.container);
        if (container && source) {
            const target = container?.querySelector(this.props.target);
            if (target) {
                const elements = {
                    container: {
                        dom: container,
                        rect: container.getBoundingClientRect()
                    },
                    target: {
                        dom: target,
                        rect: target.getBoundingClientRect()
                    },
                    source: {
                        dom: source,
                        rect: source.getBoundingClientRect()
                    }
                };
                const callout = this.callout.current;
                if (callout) {
                    elements.callout = { dom: callout, rect: callout.getBoundingClientRect() };
                }
                return elements;
            }
        }
        return undefined;
    }
    /**
     * Method calculates callout overlap with target and applies transformation to make target visible.
     */
    applyTransformation() {
        const elements = this.getElements();
        if (!elements) {
            return;
        }
        const { container, target, callout, source } = elements;
        if (callout) {
            const maxHeight = window.innerHeight - defaultProps.minPagePadding;
            const height = callout.rect.height;
            const top = source.rect.bottom;
            // Calculate if action is overlaps
            let diff = top + height - target.rect.top;
            let bottomPosition = top + callout.rect.height;
            if (diff <= 0 || bottomPosition >= maxHeight) {
                return;
            }
            // Apply additional offset to make target more visible
            bottomPosition += target.rect.height;
            if (bottomPosition <= maxHeight) {
                diff += TRANSFORMATION_OFFSET;
            }
            // Apply absolute position to fix position and avoid recentering
            if (this.props.absolute) {
                const containerStyle = container.dom.style;
                this.originalStyle = {
                    transform: containerStyle.transform,
                    position: containerStyle.position,
                    top: containerStyle.top,
                    left: containerStyle.left
                };
                containerStyle.transform = '';
                containerStyle.position = 'absolute';
                containerStyle.top = `${container.rect.top}px`;
                containerStyle.left = `${container.rect.left}px`;
            }
            // Apply placeholder element - gap to make target visible
            this.placeholder = this.createPlaceholder(diff);
            target.dom.prepend(this.placeholder);
        }
    }
    /**
     * Method resets current applied transformation.
     */
    resetTransformation() {
        const elements = this.getElements();
        if (!elements) {
            return;
        }
        const { container } = elements;
        for (const styleName in this.originalStyle) {
            const styleValue = this.originalStyle[styleName];
            if (typeof styleValue === 'string') {
                container.dom.style[styleName] = styleValue;
            }
        }
        this.originalStyle = {};
        // Remove placeholder element
        if (this.placeholder) {
            this.placeholder.remove();
            this.placeholder = undefined;
        }
    }
    /**
     * Method prevents callout dismiss/close if focus/click on target elements.
     *
     * @param event Triggered event to check.
     * @returns Returns true if callout should not be closed.
     */
    preventDismissOnEvent(event) {
        const elements = this.getElements();
        if (event.type === 'focus' && elements?.target.dom.contains(event.target)) {
            return true;
        }
        return false;
    }
}
exports.CalloutCollisionTransform = CalloutCollisionTransform;
//# sourceMappingURL=CalloutCollisionTransform.js.map