import * as i0 from '@angular/core';
import { Injectable, InjectionToken, inject, PLATFORM_ID, DOCUMENT } from '@angular/core';
import { BehaviorSubject, timer } from 'rxjs';
import { filter, map, distinctUntilChanged, takeUntil, endWith, repeat, share } from 'rxjs/operators';
import { isPlatformBrowser } from '@angular/common';
import { OverlayConfig } from '@angular/cdk/overlay';

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
/**
 * A global blink pulse generator for synchronized blinking patterns across an entire application.
 * Use to trigger any blinking by subscribing to `pulse$`.
 */
class BlinkService {
    pause$ = new BehaviorSubject(false);
    off$ = this.pause$.pipe(filter(v => v));
    on$ = this.pause$.pipe(filter(v => !v));
    /**
     * Blink pulse. Subscribe to it to toggle `on` CSS class when true, `off` CSS class when `false`.
     * Do animations using CSS transitions
     *
     * @defaultValue
     * ```
     * timer(0, 1400).pipe(
     *     map(count => count % 2 === 0),
     *     distinctUntilChanged(),
     *     takeUntil(this.off$),
     *     endWith(false),
     *     repeat({ delay: () => this.on$ }),
     *     share()
     *   )
     * ```
     */
    pulse$ = timer(0, 1400).pipe(map(count => count % 2 === 0), distinctUntilChanged(), takeUntil(this.off$), endWith(false), repeat({ delay: () => this.on$ }), share());
    /**
     * Pause the blinking.
     */
    pause() {
        this.pause$.next(true);
    }
    /**
     * Resume the blinking.
     */
    resume() {
        this.pause$.next(false);
    }
    /**
     * Whether the blinking is paused or not.
     */
    isPaused() {
        return this.pause$.value;
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: BlinkService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
    static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: BlinkService, providedIn: 'root' });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: BlinkService, decorators: [{
            type: Injectable,
            args: [{ providedIn: 'root' }]
        }] });

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
const SI_UI_STATE_STORAGE = new InjectionToken('si.ui-state.storage', {
    providedIn: 'root',
    factory: () => {
        if (isPlatformBrowser(inject(PLATFORM_ID))) {
            return new LocalStorageUIStateStorage();
        }
        return { save: () => { }, load: () => null };
    }
});
class LocalStorageUIStateStorage {
    save(stateId, data) {
        localStorage.setItem(`si.ui-state.${stateId}`, data);
    }
    load(stateId) {
        return localStorage.getItem(`si.ui-state.${stateId}`);
    }
}
/** @internal */
const SI_UI_STATE_SERVICE = new InjectionToken('si.ui-state.service');
/**
 * Service to save and load UI states.
 * @internal
 */
class SiUIStateService {
    storage = inject(SI_UI_STATE_STORAGE);
    /**
     * Saves the provided state in the storage.
     * @param stateId - The unique id or key under which the state shall be saved.
     * @param state - The state to be saved.
     * @param version - The version of the state object.
     * This can be used to migrate state objects.
     */
    save(stateId, state, version = 0) {
        return Promise.resolve(this.storage.save(stateId, JSON.stringify({
            version,
            state
        })));
    }
    /**
     * Loads and returns the state for the given stateId and version.
     * @param stateId - The unique id or key for which the state shall be loaded.
     * @param version - The version of the state object.
     * This can be used to migrate state objects.
     * @returns A Promise containing the state or undefined if the state does not exist or the version did not match.
     */
    load(stateId, version = 0) {
        // DO NOT ADD async keyword.
        // This method should stay synchronous if the storage is synchronous.
        // Otherwise, the navbar will play expand animations on load.
        const dataOrPromise = this.storage.load(stateId);
        if (dataOrPromise instanceof Promise) {
            return dataOrPromise.then(data => this.readData(data, version));
        }
        else {
            const promiseLike = {
                then: onfulfilled => {
                    const data = this.readData(dataOrPromise, version);
                    if (onfulfilled) {
                        return onfulfilled(data);
                    }
                    else {
                        return promiseLike;
                    }
                }
            };
            return promiseLike;
        }
    }
    readData(data, version) {
        if (data) {
            const parsed = JSON.parse(data);
            if (parsed.version === version) {
                return parsed.state;
            }
        }
        return undefined;
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiUIStateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
    static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiUIStateService });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: SiUIStateService, decorators: [{
            type: Injectable
        }] });
/** Enables the automatic storage of UI state for enabled components. */
const provideSiUiState = (config) => {
    return [
        { provide: SI_UI_STATE_SERVICE, useClass: SiUIStateService },
        config?.store ? { provide: SI_UI_STATE_STORAGE, useClass: config.store } : []
    ];
};

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
class TextMeasureService {
    measureCanvas;
    defaultFont;
    document = inject(DOCUMENT);
    /** Measure text width in pixel. */
    measureText(text, fontRef, overrides) {
        this.ensureCanvas();
        this.setFontStyle(fontRef, overrides);
        return Math.ceil(this.measureCanvas.measureText(text).width);
    }
    /** Get font styles for `font` CSS short-hand property. */
    getFontStyle(element, overrides) {
        const style = getComputedStyle(element);
        // note: can't use destructuring on `style` as it doesn't work on Firefox
        const fontStyle = overrides?.fontStyle ?? style.fontStyle;
        const fontVariant = overrides?.fontVariant ?? style.fontVariant;
        const fontWeight = overrides?.fontWeight ?? style.fontWeight;
        const fontSize = overrides?.fontSize ?? style.fontSize;
        const fontFamily = overrides?.fontFamily ?? style.fontFamily;
        return `${fontStyle} ${fontVariant} ${fontWeight} ${fontSize} ${fontFamily}`
            .replace(/ +/g, ' ')
            .trim();
    }
    ensureCanvas() {
        if (this.measureCanvas) {
            return;
        }
        const canvas = this.document.createElement('canvas');
        this.measureCanvas = canvas.getContext('2d');
    }
    setFontStyle(fontRef, overrides) {
        if (typeof fontRef === 'string') {
            this.measureCanvas.font = fontRef;
            return;
        }
        if (fontRef || overrides) {
            this.measureCanvas.font = this.getFontStyle(fontRef ?? this.document.body, overrides);
            return;
        }
        this.defaultFont ??= this.getFontStyle(this.document.body);
        this.measureCanvas.font = this.defaultFont;
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: TextMeasureService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
    static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: TextMeasureService, providedIn: 'root' });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: TextMeasureService, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root'
                }]
        }] });

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
/**
 * Gets the width of the scrollbar.  Nesc for windows
 * http://stackoverflow.com/a/13382873/888165
 */
class ScrollbarHelper {
    document = inject(DOCUMENT);
    /**
     * The width of the scrollbar.
     *
     * @defaultValue this.getWidth()
     */
    width = this.getWidth();
    getWidth() {
        const outer = this.document.createElement('div');
        outer.style.visibility = 'hidden';
        outer.style.width = '100px';
        outer.style.msOverflowStyle = 'scrollbar';
        this.document.body.appendChild(outer);
        const widthNoScroll = outer.offsetWidth;
        outer.style.overflow = 'scroll';
        const inner = this.document.createElement('div');
        inner.style.width = '100%';
        outer.appendChild(inner);
        const widthWithScroll = inner.offsetWidth;
        outer.parentNode?.removeChild(outer);
        return widthNoScroll - widthWithScroll;
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: ScrollbarHelper, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
    static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: ScrollbarHelper, providedIn: 'root' });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: ScrollbarHelper, decorators: [{
            type: Injectable,
            args: [{ providedIn: 'root' }]
        }] });

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */

const STATUS_ICON = {
    success: {
        icon: 'element-circle-filled',
        color: 'status-success',
        stacked: 'element-state-tick smooth-auto',
        stackedColor: 'status-success-contrast',
        background: 'bg-base-success',
        severity: 5
    },
    info: {
        icon: 'element-square-filled',
        color: 'status-info',
        stacked: 'element-state-info smooth-auto',
        stackedColor: 'status-info-contrast',
        background: 'bg-base-info',
        severity: 4
    },
    caution: {
        icon: 'element-square-45-filled',
        color: 'status-caution',
        stacked: 'element-state-exclamation-mark smooth-auto',
        stackedColor: 'status-caution-contrast',
        background: 'bg-base-caution',
        severity: 3
    },
    warning: {
        icon: 'element-triangle-filled',
        color: 'status-warning',
        stacked: 'element-state-exclamation-mark smooth-auto',
        stackedColor: 'status-warning-contrast',
        background: 'bg-base-warning',
        severity: 2
    },
    danger: {
        icon: 'element-circle-filled',
        color: 'status-danger',
        stacked: 'element-state-exclamation-mark smooth-auto',
        stackedColor: 'status-danger-contrast',
        background: 'bg-base-danger',
        severity: 1
    },
    critical: {
        icon: 'element-octagon-filled',
        color: 'status-critical',
        stacked: 'element-state-exclamation-mark smooth-auto',
        stackedColor: 'status-critical-contrast',
        background: 'bg-base-critical',
        severity: 0
    },
    progress: {
        icon: 'element-circle-filled',
        color: 'status-info',
        stacked: 'element-state-progress smooth-auto',
        stackedColor: 'status-info-contrast',
        background: 'bg-base-info',
        severity: 7
    },
    pending: {
        icon: 'element-circle-filled',
        color: 'status-caution',
        stacked: 'element-state-pause smooth-auto',
        stackedColor: 'status-caution-contrast',
        background: 'bg-base-caution',
        severity: 6
    },
    unknown: {
        icon: 'element-circle-filled',
        color: 'status-neutral',
        stacked: 'element-state-question-mark',
        stackedColor: 'text-body',
        background: 'bg-base-0',
        severity: 8
    }
};

const positionStart = {
    overlayX: 'end',
    overlayY: 'center',
    originX: 'start',
    originY: 'center'
};
const positionEnd = {
    overlayX: 'start',
    overlayY: 'center',
    originX: 'end',
    originY: 'center'
};
const positionTopCenter = {
    overlayX: 'center',
    overlayY: 'bottom',
    originX: 'center',
    originY: 'top'
};
const positionTopStart = {
    overlayX: 'start',
    overlayY: 'bottom',
    originX: 'center',
    originY: 'top'
};
const positionTopEnd = {
    overlayX: 'end',
    overlayY: 'bottom',
    originX: 'center',
    originY: 'top'
};
const positionBottomCenter = {
    overlayX: 'center',
    overlayY: 'top',
    originX: 'center',
    originY: 'bottom'
};
const positionBottomStart = {
    overlayX: 'start',
    overlayY: 'top',
    originX: 'center',
    originY: 'bottom'
};
const positionBottomEnd = {
    overlayX: 'end',
    overlayY: 'top',
    originX: 'center',
    originY: 'bottom'
};
const positions = {
    top: [
        positionTopCenter,
        positionTopStart,
        positionTopEnd,
        positionBottomCenter,
        positionBottomStart,
        positionBottomEnd,
        positionStart,
        positionEnd
    ],
    end: [
        positionEnd,
        positionTopCenter,
        positionTopStart,
        positionTopEnd,
        positionBottomCenter,
        positionBottomStart,
        positionBottomEnd,
        positionStart
    ],
    bottom: [
        positionBottomCenter,
        positionBottomStart,
        positionBottomEnd,
        positionTopCenter,
        positionTopStart,
        positionTopEnd,
        positionStart,
        positionEnd
    ],
    start: [
        positionStart,
        positionTopCenter,
        positionTopStart,
        positionTopEnd,
        positionBottomCenter,
        positionBottomStart,
        positionBottomEnd,
        positionEnd
    ],
    auto: [
        positionTopCenter,
        positionTopStart,
        positionTopEnd,
        positionBottomCenter,
        positionBottomStart,
        positionBottomEnd,
        positionStart,
        positionEnd
    ]
};

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
/**
 * @returns Returns whether animations are disabled via the CSS var. This is either set by
 * an application on low-end devices or in case the device is configured for reduced motion
 * (i.e. `@media (prefers-reduced-motion)` matches)
 */
const areAnimationsDisabled = () => {
    const style = getComputedStyle(document.documentElement);
    const flag = style.getPropertyValue('--element-animations-enabled');
    return parseInt(flag, 10) === 0;
};

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
/** */
const isRTL = (elem) => getComputedStyle(elem ?? document.documentElement).direction === 'rtl';
const correctKeyRTL = (key) => {
    if (!isRTL()) {
        return key;
    }
    return key === 'ArrowLeft' ? 'ArrowRight' : key === 'ArrowRight' ? 'ArrowLeft' : key;
};

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
/** @deprecated Use the CDK Overlay instead. */
const AXIS_X = {
    axis: 'X',
    directionRegular: 'end',
    directionReverse: 'start',
    upperBound: 'left',
    lowerBound: 'right',
    size: 'width',
    windowSize: 'innerWidth'
};
/** @deprecated Use the CDK Overlay instead. */
const AXIS_Y = {
    axis: 'Y',
    directionRegular: 'down',
    directionReverse: 'up',
    upperBound: 'top',
    lowerBound: 'bottom',
    size: 'height',
    windowSize: 'innerHeight'
};
/** @deprecated Use the CDK Overlay instead. */
const BOUNDING_RECT_WINDOW = {
    getBoundingClientRect: () => ({
        top: 0,
        left: 0,
        bottom: window.innerHeight,
        right: window.innerWidth
    })
};
/** @deprecated Use the CDK Overlay instead. */
const resolveReference = (hostElement, reference) => {
    if (reference) {
        const childReferenceCheck = hostElement.querySelector(reference);
        if (childReferenceCheck) {
            return childReferenceCheck;
        }
        const referenceCheck = hostElement.closest(reference);
        if (referenceCheck) {
            return referenceCheck;
        }
        const all = document.querySelectorAll(reference);
        return all[all.length - 1] ?? null;
    }
    return null;
};
const getScrollParentsChain = (element, axis, scrollParentsList = []) => {
    if (element) {
        const overflowStyle = getComputedStyle(element)[axis === 'X' ? 'overflowX' : 'overflowY'] || 'visible';
        if (element[axis === 'X' ? 'clientWidth' : 'clientHeight'] &&
            overflowStyle !== 'visible' &&
            overflowStyle !== 'hidden') {
            scrollParentsList.push(document.documentElement === element ? BOUNDING_RECT_WINDOW : element);
        }
        if (element !== document.documentElement) {
            getScrollParentsChain(element.dropdownParentElement ?? element.parentElement ?? document.body, axis, scrollParentsList);
        }
    }
    return scrollParentsList;
};
const getCombinedBoundingClientRect = (elements) => {
    let top = 0;
    let bottom = 0;
    let left = 0;
    let right = 0;
    if (elements.length > 0) {
        const tops = [];
        const bottoms = [];
        const lefts = [];
        const rights = [];
        elements.forEach(element => {
            const rect = element.getBoundingClientRect();
            tops.push(rect.top);
            bottoms.push(rect.bottom);
            lefts.push(rect.left);
            rights.push(rect.right);
        });
        top = Math.min(...tops);
        bottom = Math.max(...bottoms);
        left = Math.min(...lefts);
        right = Math.max(...rights);
    }
    return { top, bottom, left, right };
};
const calculatePlacementRefOuterBounds = (currentAxis, placementReferenceElement) => {
    // The chain of scroll parents of the placement ref element up to and often including the body, checking for possible overlaps.
    const placementRefScrollParents = getScrollParentsChain(placementReferenceElement, currentAxis.axis);
    const placementRefScrollParentRects = placementRefScrollParents.map(item => item.getBoundingClientRect());
    // The biggest upper bound (top, left) of all scroll parents (and viewport = 0), the point before which content will be cut off.
    const placementRefScrollParentsUpperBound = Math.max(0, ...placementRefScrollParentRects.map(item => item[currentAxis.upperBound]));
    // The smallest lower bound (bottom, right) of all scroll parents (and viewport), the point after which content will be cut off.
    const placementRefScrollParentsLowerBound = Math.min(window[currentAxis.windowSize], ...placementRefScrollParentRects.map(item => item[currentAxis.lowerBound]));
    return { upper: placementRefScrollParentsUpperBound, lower: placementRefScrollParentsLowerBound };
};
const calculateDirectionFromPlacementRef = (params) => {
    const { currentAxis, positionRegular, positionReverse, contentSize, placementRefBounds, currentDirection, rtl } = params;
    // A number showing how many visible pixels would be available from the placement ref in regular / scroll (down, end) direction
    const placementRefSpaceRegular = placementRefBounds.lower - positionRegular[currentAxis.upperBound];
    // A number showing how many visible pixels would be available from the placement ref in reverse (up, start) direction
    const placementRefSpaceReverse = positionReverse[currentAxis.upperBound] - placementRefBounds.upper;
    if (placementRefSpaceReverse < contentSize && placementRefSpaceRegular < contentSize) {
        // If there would not be enough room in both directions, always prefer regular / scroll (down, end) direction,
        // since this way the element can expand and scroll while this cannot happen if there's not enough room in front.
        return rtl ? currentAxis.directionReverse : currentAxis.directionRegular;
    }
    else if (placementRefSpaceReverse < contentSize) {
        return currentAxis.directionRegular;
    }
    else if (placementRefSpaceRegular < contentSize) {
        return currentAxis.directionReverse;
    }
    // If there would be enough room in both directions, use the set direction (or the regular one if not set).
    return currentDirection;
};
const getAbsoluteContentPosition = (params) => {
    const { direction, placement, element, align, rtl } = params;
    const elementRect = element.getBoundingClientRect();
    const start = rtl ? elementRect.right : elementRect.left;
    const end = rtl ? elementRect.left : elementRect.right;
    let relativeLeftOffset;
    if (direction === 'start' || direction === 'end') {
        relativeLeftOffset =
            placement.includes('end') || (!placement.includes('start') && direction === 'end')
                ? end
                : start;
    }
    else {
        if (placement.includes('start')) {
            relativeLeftOffset = start;
        }
        else {
            if (placement.includes('end') || align === 'end') {
                relativeLeftOffset = end;
            }
            else if (align === 'center') {
                relativeLeftOffset = elementRect.left + (elementRect.right - elementRect.left) / 2;
            }
            else {
                relativeLeftOffset = start;
            }
        }
    }
    let relativeTopOffset;
    if (direction === 'up') {
        relativeTopOffset = placement.includes('bottom') ? elementRect.bottom : elementRect.top;
    }
    else if (direction === 'start' || direction === 'end') {
        relativeTopOffset = !placement.includes('bottom') ? elementRect.top : elementRect.bottom;
    }
    else {
        relativeTopOffset = placement.includes('top') ? elementRect.top : elementRect.bottom;
    }
    return { left: relativeLeftOffset, top: relativeTopOffset };
};
const getRelativeContentPosition = (params) => {
    const { contentElement, direction, placement, placementReferenceElement, align, rtl } = params;
    const contentParent = contentElement.offsetParent ?? document.body;
    const contentParentRect = contentParent.getBoundingClientRect();
    const relativePosition = getAbsoluteContentPosition({
        direction,
        placement,
        element: placementReferenceElement,
        align,
        rtl
    });
    const leftOffset = relativePosition.left - contentParentRect.left + contentParent.scrollLeft;
    const topOffset = relativePosition.top - contentParentRect.top + contentParent.scrollTop;
    return { left: leftOffset, top: topOffset };
};
/** @deprecated Use the CDK Overlay instead. */
const getContentPositionString = (params) => {
    const { contentElement, direction, placement, placementReferenceElement, align, rtl } = params;
    const position = getRelativeContentPosition({
        contentElement,
        direction,
        placement,
        placementReferenceElement,
        align,
        rtl: rtl ?? isRTL()
    });
    return `translate3d(${position.left}px, ${position.top}px, 0px)`;
};
/** @deprecated Use the CDK Overlay instead. */
const responsivelyCheckDirection = (params) => {
    const { isScrolling, currentDirection, contentElements, hostElement, placement, placementReferenceElement, align, responsiveDirectionToPlacement, closeOnPlacementReferenceScrollOut, closeOnContentScrollOut, minSpaceThresholdFactor, placementReverse, rtl } = params;
    const actualRtl = rtl ?? isRTL();
    let responsiveDirection;
    const actualCurrentDirection = actualRtl
        ? currentDirection === 'start'
            ? 'end'
            : currentDirection === 'end'
                ? 'start'
                : currentDirection
        : currentDirection;
    // Defines how the properties to access are named in the current axis.
    const currentAxis = currentDirection === 'start' || currentDirection === 'end' ? AXIS_X : AXIS_Y;
    // The combined (enclosing) client rect for all component contents.
    const contentsRect = getCombinedBoundingClientRect(contentElements);
    // The chain of scroll parents of the container host element up to and often including the body, checking for possible overlaps.
    const containerScrollParents = getScrollParentsChain(hostElement, currentAxis.axis);
    const containerScrollParentRects = containerScrollParents.map(item => item.getBoundingClientRect());
    // The biggest upper bound (top, left) of all scroll parents (and viewport = 0), the point before which content will be cut off.
    const scrollParentsUpperBound = Math.max(0, ...containerScrollParentRects.map(item => item[currentAxis.upperBound]));
    // The smallest lower bound (bottom, right) of all scroll parents (and viewport), the point after which content will be cut off.
    const scrollParentsLowerBound = Math.min(window[currentAxis.windowSize], ...containerScrollParentRects.map(item => item[currentAxis.lowerBound]));
    // The point from which the component will be opened if opening in regular / scroll (down, end) direction.
    // Influenced by `componentPlacementReference`, `componentPlacement` and `componentAlign`.
    const positionRegular = getAbsoluteContentPosition({
        direction: currentAxis.directionRegular,
        placement,
        element: placementReferenceElement,
        align
    });
    // The point from which the component will be opened if opening in reverse (up, start) direction.
    // Influenced by `componentPlacementReference`, `componentPlacement` and `componentAlign`.
    const positionReverse = getAbsoluteContentPosition({
        direction: currentAxis.directionReverse,
        placement: placementReverse ?? placement,
        element: placementReferenceElement,
        align
    });
    // The enclosing size (height, width) of all contents combined
    const contentsSize = contentsRect[currentAxis.lowerBound] - contentsRect[currentAxis.upperBound];
    // A number showing how many visible pixels would be available in regular / scroll (down, end) direction
    const spaceRegular = scrollParentsLowerBound - positionRegular[currentAxis.upperBound];
    // A number showing how many visible pixels would be available in reverse (up, start) direction
    const spaceReverse = positionReverse[currentAxis.upperBound] - scrollParentsUpperBound;
    let placementRefBounds;
    if (spaceReverse < contentsSize && spaceRegular < contentsSize) {
        // If there would not be enough room in both directions, always prefer regular / scroll (down, end) direction,
        // since this way the element can expand and scroll while this cannot happen if there's not enough room in front.
        responsiveDirection = actualRtl ? currentAxis.directionReverse : currentAxis.directionRegular;
    }
    else if (minSpaceThresholdFactor) {
        const contentsSizeWithThreshold = contentsSize + minSpaceThresholdFactor * contentsSize;
        if (spaceReverse < contentsSizeWithThreshold && spaceRegular < contentsSizeWithThreshold) {
            // If a threshold is set and there would not be enough space including the threshold in both directions
            // use the direction with more space
            if (spaceReverse < spaceRegular) {
                responsiveDirection = currentAxis.directionRegular;
            }
            else {
                responsiveDirection = currentAxis.directionReverse;
            }
        }
        else if (spaceReverse < contentsSizeWithThreshold) {
            responsiveDirection = currentAxis.directionRegular;
        }
        else if (spaceRegular < contentsSizeWithThreshold) {
            responsiveDirection = currentAxis.directionReverse;
        }
    }
    if (!responsiveDirection) {
        if (spaceReverse < contentsSize) {
            responsiveDirection = currentAxis.directionRegular;
        }
        else if (spaceRegular < contentsSize) {
            responsiveDirection = currentAxis.directionReverse;
        }
        else {
            if (responsiveDirectionToPlacement &&
                placementReferenceElement &&
                hostElement !== placementReferenceElement) {
                placementRefBounds = calculatePlacementRefOuterBounds(currentAxis, placementReferenceElement);
                responsiveDirection = calculateDirectionFromPlacementRef({
                    currentAxis,
                    positionRegular,
                    positionReverse,
                    contentSize: contentsSize,
                    placementRefBounds,
                    currentDirection: actualCurrentDirection,
                    rtl: actualRtl
                });
            }
            else {
                // If there would be enough room in both directions, use the set direction (or the regular one if not set).
                responsiveDirection = actualCurrentDirection;
            }
        }
    }
    let close = false;
    if (isScrolling) {
        // Check if the container host or placement reference is hidden and close the component. (Mostly done when scrolling.)
        if (closeOnPlacementReferenceScrollOut &&
            placementReferenceElement &&
            hostElement !== placementReferenceElement) {
            placementRefBounds ??= calculatePlacementRefOuterBounds(currentAxis, placementReferenceElement);
            const placementRefRect = placementReferenceElement.getBoundingClientRect();
            // A number showing how many visible pixels of the placement ref would be shown in reverse (up, start) direction
            const placementRefVisibleTop = placementRefRect[currentAxis.lowerBound] - placementRefBounds.upper;
            // A number showing how many visible pixels of the placement ref would be shown in regular / scroll (down, end) direction
            const placementRefVisibleBottom = placementRefBounds.lower - placementRefRect[currentAxis.upperBound];
            if (placementRefVisibleTop < 0 || placementRefVisibleBottom < 0) {
                // Close the component if the placement ref is not visible.
                close = true;
            }
        }
        if (!close && closeOnContentScrollOut) {
            // A number showing how many visible pixels would be available the other way if set to regular / scroll (down, end) direction
            const spaceRegularOtherSide = scrollParentsLowerBound - positionReverse[currentAxis.upperBound];
            // A number showing how many visible pixels would be available the other way if set to reverse (up, start) direction
            const spaceReverseOtherSide = positionRegular[currentAxis.upperBound] - scrollParentsUpperBound;
            if (spaceRegularOtherSide < 0 || spaceReverseOtherSide < 0) {
                // Close the component if there is not enough space even in the other direction.
                close = true;
            }
        }
    }
    responsiveDirection = actualRtl
        ? responsiveDirection === 'start'
            ? 'end'
            : responsiveDirection === 'end'
                ? 'start'
                : responsiveDirection
        : responsiveDirection;
    return { responsiveDirection, close };
};

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
// Adds a window listener which can optionally be active, returns the unregister function.
// For some events (e.g. "touchmove") an explicit "passive: false" is required in order to
// be able to do $event.preventDefault(). Unfortunately there is no way in Angular to pass
// options to Rendrer2/EventManager event handling.
const listenGlobal = (eventName, handler, active) => {
    let opts = false;
    if (active !== undefined) {
        opts = { passive: !active };
    }
    window.addEventListener(eventName, handler, opts);
    return () => {
        window.removeEventListener(eventName, handler, opts);
    };
};

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */
/* eslint-disable prefer-arrow/prefer-arrow-functions */
function makePositionStrategy(elementRef, overlay, placement, constrain = false, center = true) {
    if (!elementRef?.nativeElement) {
        return overlay.position().global().centerHorizontally().centerVertically();
    }
    const popoverPositions = getOverlayPositions(elementRef, placement, center);
    const positionStrategy = overlay
        .position()
        .flexibleConnectedTo(elementRef)
        .withPush(false)
        .withGrowAfterOpen(true)
        .withFlexibleDimensions(constrain)
        .withPositions(popoverPositions);
    if (constrain) {
        positionStrategy.withViewportMargin(8);
    }
    return positionStrategy;
}
function makeOverlay(positionStrategy, overlay, hasBackdrop) {
    const config = new OverlayConfig();
    config.positionStrategy = positionStrategy;
    config.scrollStrategy = overlay.scrollStrategies.reposition();
    config.direction = isRTL() ? 'rtl' : 'ltr';
    if (hasBackdrop) {
        config.hasBackdrop = true;
        config.backdropClass = 'cdk-overlay-transparent-backdrop';
    }
    else {
        config.hasBackdrop = false;
    }
    return overlay.create(config);
}
function getOverlay(elementRef, overlay, hasBackdrop, placement, constrain = false, center = true) {
    const positionStrategy = makePositionStrategy(elementRef, overlay, placement, constrain, center);
    return makeOverlay(positionStrategy, overlay, hasBackdrop);
}
function getPositionStrategy(overlayref) {
    return overlayref.getConfig().positionStrategy;
}
function getOverlayPositions(elementRef, placement, center = true) {
    if (elementRef.nativeElement && center) {
        const rtl = isRTL();
        const halfWidth = Math.round(elementRef.nativeElement.offsetWidth / 2);
        positionTopStart.offsetX = positionBottomStart.offsetX = halfWidth * (rtl ? 1 : -1);
        positionTopEnd.offsetX = positionBottomEnd.offsetX = halfWidth * (rtl ? -1 : 1);
    }
    else {
        positionTopStart.offsetX = undefined;
        positionTopEnd.offsetX = undefined;
        positionBottomStart.offsetX = undefined;
        positionBottomEnd.offsetX = undefined;
    }
    return typeof placement === 'string' ? positions[placement] : placement;
}
function hasTrigger(trigger, triggers) {
    return (triggers?.split(/\s+/) ?? []).includes(trigger);
}
/**
 * calculates the arrow position from left/right for tooltips, popovers, etc
 * @param change - the event from the position strategy
 * @param overlay - ElementRef for the overlay content, i.e. the popover/tooltip component
 * @param anchor - ElementRef for the anchoring element, i.e. the trigger of the popover/tooltip
 */
function calculateOverlayArrowPosition(change, overlay, anchor) {
    if (anchor && ['bottom', 'top'].includes(change.connectionPair.originY)) {
        // Calculate offset to the anchor element center
        const anchorRect = anchor.nativeElement.getBoundingClientRect();
        const overlayRect = overlay.nativeElement.getBoundingClientRect();
        const center = anchorRect.left + anchorRect.width / 2;
        // Position arrow centered to the anchor element
        // prettier-ignore
        return isRTL()
            ? { right: overlayRect.right - center }
            : { left: center - overlayRect.left };
    }
    const offsetX = change.connectionPair.offsetX;
    if (offsetX) {
        // prettier-ignore
        return offsetX < 0
            ? { left: -offsetX }
            : { right: offsetX };
    }
    return {};
}

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */

// note: this _must_ be a function, not an arrow
// eslint-disable-next-line
function WebComponentContentChildren(host) {
    // holds the Type information of child component and the property name of parent component which is used to hold it.
    return (...args) => {
        args[0].__contentQuery = {
            host,
            prop: args[1]
        };
    };
}

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */

/**
 * Copyright (c) Siemens 2016 - 2026
 * SPDX-License-Identifier: MIT
 */

/**
 * Generated bundle index. Do not edit.
 */

export { AXIS_X, AXIS_Y, BOUNDING_RECT_WINDOW, BlinkService, SI_UI_STATE_SERVICE, STATUS_ICON, ScrollbarHelper, TextMeasureService, WebComponentContentChildren, areAnimationsDisabled, calculateOverlayArrowPosition, correctKeyRTL, getContentPositionString, getOverlay, getOverlayPositions, getPositionStrategy, hasTrigger, isRTL, listenGlobal, makeOverlay, makePositionStrategy, positionBottomCenter, positionBottomEnd, positionBottomStart, positionTopCenter, positionTopEnd, positionTopStart, positions, provideSiUiState, resolveReference, responsivelyCheckDirection };
//# sourceMappingURL=siemens-element-ng-common.mjs.map
