export class PortalUtils {
    static calculateAvailableSpace(referenceElement) {
        const rect = referenceElement.getBoundingClientRect();
        const viewportHeight = window.innerHeight;
        const viewportWidth = window.innerWidth;
        const spaceBelow = viewportHeight - rect.bottom;
        const spaceAbove = rect.top;
        const spaceRight = viewportWidth - rect.right;
        const spaceLeft = rect.left;
        return { spaceAbove, spaceBelow, spaceLeft, spaceRight, viewportHeight, viewportWidth };
    }
    static getOptimalPlacement(referenceElement) {
        const { spaceAbove, spaceBelow, spaceLeft, spaceRight } = this.calculateAvailableSpace(referenceElement);
        if (spaceBelow >= 200 && spaceBelow >= spaceAbove) {
            return 'bottom';
        }
        else if (spaceAbove >= 200 && spaceAbove > spaceBelow) {
            return 'top';
        }
        if (spaceRight >= 200 && spaceRight >= spaceLeft) {
            return 'right';
        }
        else if (spaceLeft >= 200) {
            return 'left';
        }
        return 'bottom';
    }
    static findBoundaryElements(component) {
        const boundaryElements = [];
        let currentElement = component.parentElement;
        while (currentElement && currentElement !== document.body) {
            const computedStyle = window.getComputedStyle(currentElement);
            const overflow = computedStyle.overflow;
            const overflowY = computedStyle.overflowY;
            const overflowX = computedStyle.overflowX;
            if (overflow === 'auto' || overflow === 'scroll' ||
                overflowY === 'auto' || overflowY === 'scroll' ||
                overflowX === 'auto' || overflowX === 'scroll') {
                boundaryElements.push(currentElement);
            }
            if (currentElement.hasAttribute('data-floating-boundary') ||
                currentElement.classList.contains('floating-boundary') ||
                currentElement.classList.contains('scroll-container')) {
                boundaryElements.push(currentElement);
            }
            currentElement = currentElement.parentElement;
        }
        return boundaryElements.length > 0 ? boundaryElements : undefined;
    }
    static calculateOptimalHeight(referenceRect, viewportHeight, placement) {
        const spaceBelow = viewportHeight - (referenceRect.y + referenceRect.height);
        const spaceAbove = referenceRect.y;
        if (placement.startsWith('top')) {
            return Math.max(spaceAbove - 20, 100);
        }
        else if (placement.startsWith('bottom')) {
            return Math.max(spaceBelow - 20, 100);
        }
        else if (placement.startsWith('left') || placement.startsWith('right')) {
            return Math.max(Math.min(spaceAbove, spaceBelow) - 20, 100);
        }
        return Math.max(Math.min(spaceAbove, spaceBelow) - 20, 100);
    }
    static extractStylesAsCSS(styles) {
        if (typeof styles === 'string') {
            return styles;
        }
        if (Array.isArray(styles)) {
            return styles.map(style => this.extractStylesAsCSS(style)).join('\n');
        }
        if (styles && typeof styles === 'object' && styles.cssText) {
            return styles.cssText;
        }
        return '';
    }
    static generateStyleId() {
        return `nile-dropdown-styles-${Math.random().toString(36).substring(2, 11)}`;
    }
    static isPositioningOptimal(placement, referenceElement) {
        const { spaceAbove, spaceBelow, spaceLeft, spaceRight } = this.calculateAvailableSpace(referenceElement);
        const isAbove = placement.startsWith('top');
        const isBelow = placement.startsWith('bottom');
        const isLeft = placement.startsWith('left');
        const isRight = placement.startsWith('right');
        if (isAbove && spaceBelow > spaceAbove)
            return false;
        if (isBelow && spaceAbove > spaceBelow)
            return false;
        if (isLeft && spaceRight > spaceLeft)
            return false;
        if (isRight && spaceLeft > spaceRight)
            return false;
        return true;
    }
    static applyCollisionData(element, middlewareData, placement) {
        if (middlewareData.flip) {
            const { overflows } = middlewareData.flip;
            element.setAttribute('data-placement', placement);
            if (overflows && overflows.length > 0) {
                const overflowPlacements = overflows.map(overflow => overflow.placement).join(',');
                element.setAttribute('data-overflow', overflowPlacements);
            }
            else {
                element.removeAttribute('data-overflow');
            }
        }
        if (middlewareData.shift) {
            const { x, y } = middlewareData.shift;
            if (x !== undefined && y !== undefined && (x !== 0 || y !== 0)) {
                element.setAttribute('data-shift', `${x},${y}`);
            }
            else {
                element.removeAttribute('data-shift');
            }
        }
        if (middlewareData.size) {
            const { availableWidth, availableHeight } = middlewareData.size;
            if (availableWidth !== undefined) {
                element.setAttribute('data-available-width', availableWidth.toString());
            }
            if (availableHeight !== undefined) {
                element.setAttribute('data-available-height', availableHeight.toString());
            }
        }
    }
}
export class PortalContentUtils {
    static createPortalPanel(component) {
        // Find the panel slot content (typically a nile-menu)
        const panelSlot = component.shadowRoot?.querySelector('.dropdown__panel');
        if (!panelSlot) {
            // Fallback: try to find in light DOM
            const slot = component.querySelector('[slot]');
            if (!slot || slot.getAttribute('slot') === 'trigger') {
                return document.createElement('div');
            }
        }
        // Get assigned elements from the slot
        let assignedElements = panelSlot?.assignedElements({ flatten: true }) || [];
        // If no assigned elements, try direct children that aren't in trigger slot
        if (assignedElements.length === 0) {
            const children = Array.from(component.children);
            assignedElements = children.filter(child => {
                const slot = child.getAttribute('slot');
                return !slot || slot !== 'trigger';
            });
        }
        // Create a container for the cloned panel
        const panelContainer = document.createElement('div');
        panelContainer.className = 'dropdown__panel';
        panelContainer.setAttribute('part', 'panel');
        panelContainer.setAttribute('aria-hidden', 'false');
        panelContainer.setAttribute('aria-labelledby', 'dropdown');
        // Clone all assigned elements
        assignedElements.forEach((element) => {
            const clonedElement = element.cloneNode(true);
            panelContainer.appendChild(clonedElement);
        });
        return panelContainer;
    }
    static updatePortalPanel(clonedPanel, component) {
        if (!clonedPanel)
            return;
        // Clear existing content
        clonedPanel.innerHTML = '';
        // Re-clone the panel content
        const panelSlot = component.shadowRoot?.querySelector('.dropdown__panel');
        let assignedElements = panelSlot?.assignedElements({ flatten: true }) || [];
        if (assignedElements.length === 0) {
            const children = Array.from(component.children);
            assignedElements = children.filter(child => {
                const slot = child.getAttribute('slot');
                return !slot || slot !== 'trigger';
            });
        }
        assignedElements.forEach((element) => {
            const clonedElement = element.cloneNode(true);
            clonedPanel.appendChild(clonedElement);
        });
    }
}
export class PortalEventUtils {
    static setupPortalEventListeners(clonedPanel, component) {
        if (!clonedPanel)
            return;
        this.setupMenuSelectListeners(clonedPanel, component);
        this.setupKeyDownListeners(clonedPanel, component);
    }
    static setupMenuSelectListeners(clonedPanel, component) {
        if (!clonedPanel)
            return;
        // Listen for nile-select events from menu items
        clonedPanel.addEventListener('nile-select', (event) => {
            const customEvent = event;
            // Forward the event to the original component
            if (component.handlePanelSelect) {
                component.handlePanelSelect(customEvent);
            }
        });
    }
    static setupKeyDownListeners(clonedPanel, component) {
        if (!clonedPanel)
            return;
        // Listen for keydown events (like Escape)
        clonedPanel.addEventListener('keydown', (event) => {
            if (component.handleKeyDown) {
                component.handleKeyDown(event);
            }
        });
    }
}
//# sourceMappingURL=portal-utils.js.map