// #region Imports
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import { arrow, autoUpdate, computePosition, flip, offset, platform, shift, size } from '@floating-ui/dom';
import { fadeIn, fadeOut } from '../../../../Animations/Presets/Fade';
import { Emit } from '../../../../Events/Decorators/EmitDecorator';
import { on, HTMLElementEventEmitter } from '@breadstone/mosaik-elements';
import { Animatable } from '../../../Behaviors/Animatable';
import { Elevatable } from '../../../Behaviors/Elevatable';
import { Attribute } from '../../../Decorators/AttributeDecorator';
import { Component } from '../../../Decorators/ComponentDecorator';
import { QueryChild } from '../../../Decorators/QueryChildDecorator';
import { Property } from '../../../Decorators/PropertyDecorator';
import { Watch } from '../../../Decorators/WatchDecorator';
import { ElevationWeight } from '../../../Types/ElevationWeight';
import { FloatingArrowPlacement } from '../../../Types/FloatingArrowPlacement';
import { FloatingAutoSize } from '../../../Types/FloatingAutoSize';
import { FloatingFlipFallbackStrategy } from '../../../Types/FloatingFlipFallbackStrategy';
import { FloatingSync } from '../../../Types/FloatingSync';
import { Placement } from '../../../Types/Placement';
import { CustomElement } from '../../Abstracts/CustomElement';
import { ElevationElement } from '../Elevation/ElevationElement';
import { floatingElementTemplate } from './FloatingElementTemplate';
import { floatingElementJoyStyle } from './Themes/FloatingElement.Joy';
import { floatingElementRetroStyle } from './Themes/FloatingElement.Retro';
import { floatingElementCosmopolitanStyle } from './Themes/FloatingElement.Cosmopolitan';
import { Themeable } from '../../../Behaviors/Themeable';
// #endregion
/**
 * Floating - Refers to UI elements that appear to "float" above other content, often used for action buttons or labels.
 *
 * @element mosaik-floating
 *
 * @fires repositioned - Called when the element is repositioned.
 * @fires activeChanged - Called when the active state is changed.
 *
 * @public
 */
let FloatingElement = class FloatingElement extends Themeable(Animatable(Elevatable(CustomElement))) {
    // #region Fields
    _arrowElement;
    _bodyElement;
    _repositioned;
    _activeChanged;
    _anchorElement;
    _anchor;
    _active;
    _distance;
    _placement;
    _skidding;
    _arrow;
    _arrowPadding;
    _flip;
    _isFullScreen;
    _flipFallbackPlacements;
    _flipFallbackStrategy;
    _arrowPlacement;
    _flipBoundary;
    _flipPadding;
    _shift;
    _shiftPadding;
    _shiftBoundary;
    _autoSize;
    _sync;
    _maxWidth;
    _maxHeight;
    _autoSizeBoundary;
    _cleanup;
    _bodyClickSubscription;
    _strategy;
    _autoSizePadding;
    // #endregion
    // #region Ctor
    /**
     * @public
     */
    constructor() {
        super();
        this.elevation = ElevationWeight.Regular;
        this._anchorElement = null;
        this._anchor = null;
        this._active = false;
        this._distance = 0;
        this._skidding = 0;
        this._placement = Placement.Top;
        this._arrow = false;
        this._arrowPadding = 12;
        this._flip = false;
        this._isFullScreen = false;
        this._flipFallbackPlacements = [];
        this._flipFallbackStrategy = FloatingFlipFallbackStrategy.BestFit;
        this._arrowPlacement = FloatingArrowPlacement.Anchor;
        this._flipBoundary = null;
        this._flipPadding = 0;
        this._shift = false;
        this._shiftBoundary = null;
        this._shiftPadding = 0;
        this._autoSize = FloatingAutoSize.None;
        this._sync = FloatingSync.None;
        this._autoSizeBoundary = null;
        this._maxWidth = null;
        this._maxHeight = null;
        this._repositioned = new HTMLElementEventEmitter(this, 'repositioned');
        this._activeChanged = new HTMLElementEventEmitter(this, 'activeChanged');
        this._bodyClickSubscription = null;
        this._strategy = 'absolute';
        this._autoSizePadding = 0;
    }
    // #endregion
    // #region Properties
    /**
     * Returns the `{@link is}` property.
     * The `{@link is}` property represents natural name of this element.
     *
     * @public
     * @static
     * @readonly
     */
    static get is() {
        return 'mosaik-floating';
    }
    /**
     * Gets or sets the `anchor` property.
     * The element the popup will be anchored to. If the anchor lives outside of the popup, you can provide its `id` or a
     * reference to it here. If the anchor lives inside the popup, use the `anchor` slot instead.
     *
     * @public
     */
    get anchor() {
        return this._anchor;
    }
    set anchor(value) {
        if (this._anchor !== value) {
            this._anchor = value;
            this.requestUpdate('anchor');
        }
    }
    /**
     * Gets or sets the `active` property.
     * Activates the positioning logic and shows the popup. When this attribute is removed, the positioning logic is torn
     * down and the popup will be hidden.
     *
     * @public
     * @attr
     */
    get active() {
        return this._active;
    }
    set active(value) {
        if (this._active !== value) {
            this._active = value;
            this.requestUpdate('active');
        }
    }
    /**
     * The preferred placement of the popup. Note that the actual placement will vary as configured to keep the
     * panel inside of the viewport.
     *
     * @public
     * @attr
     */
    get placement() {
        return this._placement;
    }
    set placement(value) {
        if (this._placement !== value) {
            this._placement = value;
            this.requestUpdate('placement');
        }
    }
    /**
     * Determines how the popup is positioned. The `absolute` strategy works well in most cases, but if overflow is
     * clipped, using a `fixed` position strategy can often workaround it.
     *
     * @public
     * @attr
     */
    get strategy() {
        return this._strategy;
    }
    set strategy(value) {
        if (this._strategy !== value) {
            this._strategy = value;
            this.requestUpdate('strategy');
        }
    }
    /**
     * The distance in pixels from which to offset the panel away from its anchor.
     *
     * @public
     */
    get distance() {
        return this._distance;
    }
    set distance(value) {
        if (this._distance !== value) {
            this._distance = value;
            this.requestUpdate('distance');
        }
    }
    /**
     * The distance in pixels from which to offset the panel along its anchor.
     *
     * @public
     */
    get skidding() {
        return this._skidding;
    }
    set skidding(value) {
        if (this._skidding !== value) {
            this._skidding = value;
            this.requestUpdate('skidding');
        }
    }
    /**
     * Attaches an arrow to the popup. The arrow's size and color can be customized using the `--arrow-size` and
     * `--arrow-color` custom properties. For additional customizations, you can also target the arrow using
     * `::part(arrow)` in your stylesheet.
     *
     * @public
     */
    get arrow() {
        return this._arrow;
    }
    set arrow(value) {
        if (this._arrow !== value) {
            this._arrow = value;
            this.requestUpdate('arrow');
        }
    }
    /**
     * Gets or sets the `isFullScreen` property.
     *
     * @public
     * @attr
     */
    get isFullScreen() {
        return this._isFullScreen;
    }
    set isFullScreen(value) {
        if (this._isFullScreen !== value) {
            this._isFullScreen = value;
            this.requestUpdate('isFullScreen');
        }
    }
    /**
     * The amount of padding between the arrow and the edges of the popup. If the popup has a border-radius, for example,
     * this will prevent it from overflowing the corners.
     *
     * @public
     * @attr
     */
    get arrowPadding() {
        return this._arrowPadding;
    }
    set arrowPadding(value) {
        if (this._arrowPadding !== value) {
            this._arrowPadding = value;
            this.requestUpdate('arrowPadding');
        }
    }
    /**
     * When set, placement of the popup will flip to the opposite site to keep it in view. You can use
     * `flipFallbackPlacements` to further configure how the fallback placement is determined.
     *
     * @public
     * @attr
     */
    get flip() {
        return this._flip;
    }
    set flip(value) {
        if (this._flip !== value) {
            this._flip = value;
            this.requestUpdate('flip');
        }
    }
    /**
     * If the preferred placement doesn't fit, popup will be tested in these fallback placements until one fits. Must be a
     * string of any number of placements separated by a space, e.g. "top bottom left". If no placement fits, the flip
     * fallback strategy will be used instead.
     *
     * @public
     * @attr
     * */
    get flipFallbackPlacements() {
        return this._flipFallbackPlacements;
    }
    set flipFallbackPlacements(value) {
        if (this._flipFallbackPlacements !== value) {
            this._flipFallbackPlacements = value;
            this.requestUpdate('flipFallbackPlacements');
        }
    }
    /**
     * The placement of the arrow. The default is `anchor`, which will align the arrow as close to the center of the
     * anchor as possible, considering available space and `arrow-padding`. A value of `start`, `end`, or `center` will
     * align the arrow to the start, end, or center of the popover instead.
     *
     * @public
     * @attr
     */
    get arrowPlacement() {
        return this._arrowPlacement;
    }
    set arrowPlacement(value) {
        if (this._arrowPlacement !== value) {
            this._arrowPlacement = value;
            this.requestUpdate('arrowPlacement');
        }
    }
    /**
     * When neither the preferred placement nor the fallback placements fit, this value will be used to determine whether
     * the popup should be positioned using the best available fit based on available space or as it was initially
     * preferred.
     *
     * @public
     * @attr
     */
    get flipFallbackStrategy() {
        return this._flipFallbackStrategy;
    }
    set flipFallbackStrategy(value) {
        if (this._flipFallbackStrategy !== value) {
            this._flipFallbackStrategy = value;
            this.requestUpdate('flipFallbackStrategy');
        }
    }
    /**
     * The flip boundary describes clipping element(s) that overflow will be checked relative to when flipping. By
     * default, the boundary includes overflow ancestors that will cause the element to be clipped. If needed, you can
     * change the boundary by passing a reference to one or more elements to this property.
     *
     * @public
     */
    get flipBoundary() {
        return this._flipBoundary;
    }
    set flipBoundary(value) {
        if (this._flipBoundary !== value) {
            this._flipBoundary = value;
            this.requestUpdate('flipBoundary');
        }
    }
    /**
     * The amount of padding, in pixels, to exceed before the flip behavior will occur.
     *
     * @public
     * @attr
     */
    get flipPadding() {
        return this._flipPadding;
    }
    set flipPadding(value) {
        if (this._flipPadding !== value) {
            this._flipPadding = value;
            this.requestUpdate('flipPadding');
        }
    }
    /**
     * Moves the popup along the axis to keep it in view when clipped.
     *
     * @public
     * @attr
     */
    get shift() {
        return this._shift;
    }
    set shift(value) {
        if (this._shift !== value) {
            this._shift = value;
            this.requestUpdate('shift');
        }
    }
    /**
     * The shift boundary describes clipping element(s) that overflow will be checked relative to when shifting. By
     * default, the boundary includes overflow ancestors that will cause the element to be clipped. If needed, you can
     * change the boundary by passing a reference to one or more elements to this property.
     *
     * @public
     */
    get shiftBoundary() {
        return this._shiftBoundary;
    }
    set shiftBoundary(value) {
        if (this._shiftBoundary !== value) {
            this._shiftBoundary = value;
            this.requestUpdate('shiftBoundary');
        }
    }
    /**
     * The amount of padding, in pixels, to exceed before the shift behavior will occur.
     *
     * @public
     * @attr
     */
    get shiftPadding() {
        return this._shiftPadding;
    }
    set shiftPadding(value) {
        if (this._shiftPadding !== value) {
            this._shiftPadding = value;
            this.requestUpdate('shiftPadding');
        }
    }
    /**
     * When set, this will cause the popup to automatically resize itself to prevent it from overflowing.
     *
     * @public
     * @attr
     */
    get autoSize() {
        return this._autoSize;
    }
    set autoSize(value) {
        if (this._autoSize !== value) {
            this._autoSize = value;
            this.requestUpdate('autoSize');
        }
    }
    /**
     * Syncs the popup's width or height to that of the anchor element.
     *
     * @public
     * @attr
     */
    get sync() {
        return this._sync;
    }
    set sync(value) {
        if (this._sync !== value) {
            this._sync = value;
            this.requestUpdate('sync');
        }
    }
    /**
     * The auto-size boundary describes clipping element(s) that overflow will be checked relative to when resizing. By
     * default, the boundary includes overflow ancestors that will cause the element to be clipped. If needed, you can
     * change the boundary by passing a reference to one or more elements to this property.
     *
     * @public
     */
    get autoSizeBoundary() {
        return this._autoSizeBoundary;
    }
    set autoSizeBoundary(value) {
        if (this._autoSizeBoundary !== value) {
            this._autoSizeBoundary = value;
            this.requestUpdate('autoSizeBoundary');
        }
    }
    /**
     * The amount of padding, in pixels, to exceed before the auto-size behavior will occur.
     *
     * @public
     * @attr
     */
    get autoSizePadding() {
        return this._autoSizePadding;
    }
    set autoSizePadding(value) {
        if (this._autoSizePadding !== value) {
            this._autoSizePadding = value;
            this.requestUpdate('autoSizePadding');
        }
    }
    /**
     * The maximum width of the popup. When the popup's width exceeds this value, it will be clipped.
     *
     * @public
     * @attr
     */
    get maxWidth() {
        return this._maxWidth;
    }
    set maxWidth(value) {
        if (this._maxWidth !== value) {
            this._maxWidth = value;
            this.requestUpdate('maxWidth');
        }
    }
    /**
     * The maximum height of the popup. If the content is taller than this value, it will scroll vertically.
     *
     * @public
     * @attr
     */
    get maxHeight() { return this._maxHeight; }
    set maxHeight(value) {
        if (this._maxHeight !== value) {
            this._maxHeight = value;
            this.requestUpdate('maxHeight');
        }
    }
    /**
     * Called when the popup is repositioned.
     * Provides reference to `this` as event argument.
     *
     * @public
     * @readonly
     * @eventProperty
     */
    get repositioned() {
        return this._repositioned;
    }
    /**
     * Called when the active state of the popup changes.
     * Provides reference to `{@link IEventDetail}` as event detail.
     *
     * @public
     * @readonly
     * @eventProperty
     */
    get activeChanged() {
        return this._activeChanged;
    }
    // #endregion
    // #region Methods
    /**
     * Opens the popup.
     *
     * @public
     */
    open() {
        this.active = true;
    }
    /**
     * Closes the popup.
     *
     * @public
     */
    close() {
        this.active = false;
    }
    /**
     * Forces the popup to recalculate and reposition itself.
     *
     * @public
     */
    reposition() {
        // Nothing to do if the popup is inactive or the anchor doesn't exist
        if (!this.active || !this._anchorElement) {
            return;
        }
        //
        // NOTE: Floating UI middlewares are order dependent: https://floating-ui.com/docs/middleware
        //
        const middleware = [
            // The offset middleware goes first
            offset({
                mainAxis: this.distance,
                crossAxis: this.skidding
            })
        ];
        // First we sync width/height
        if (this.maxWidth || this.maxHeight) {
            middleware.push(size({
                apply: ({ rects }) => {
                    if (this.sync !== FloatingSync.None) {
                        this._bodyElement.style.width = this.sync === FloatingSync.Width || this.sync === FloatingSync.Both
                            ? `${rects.reference.width}px`
                            : '';
                        this._bodyElement.style.height = this.sync === FloatingSync.Height || this.sync === FloatingSync.Both
                            ? `${rects.reference.height}px`
                            : '';
                    }
                    if (this.maxWidth && this.maxWidth !== 'auto') {
                        this._bodyElement.style.maxWidth = this.maxWidth.toString();
                    }
                    else {
                        this._bodyElement.style.maxWidth = '';
                    }
                    if (this.maxHeight && this.maxHeight !== 'auto') {
                        this._bodyElement.style.maxHeight = this.maxHeight.toString();
                    }
                    else {
                        this._bodyElement.style.maxHeight = '';
                    }
                }
            }));
        }
        else {
            // Cleanup styles if we're not matching width/height
            this._bodyElement.style.width = '';
            this._bodyElement.style.height = '';
        }
        // Then we flip
        if (this.flip) {
            middleware.push(flip({
                boundary: this.flipBoundary ?? undefined,
                fallbackPlacements: this.flipFallbackPlacements,
                fallbackStrategy: this.flipFallbackStrategy === FloatingFlipFallbackStrategy.BestFit ? 'bestFit' : 'initialPlacement',
                padding: this.flipPadding
            }));
        }
        // Then we shift
        if (this.shift) {
            middleware.push(shift({
                boundary: this.shiftBoundary ?? undefined,
                padding: this.shiftPadding
            }));
        }
        // Now we adjust the size as needed
        if (this.autoSize !== FloatingAutoSize.None) {
            middleware.push(size({
                boundary: this.autoSizeBoundary ?? undefined,
                padding: this.autoSizePadding,
                apply: ({ availableWidth, availableHeight }) => {
                    if (this.autoSize === FloatingAutoSize.Vertical || this.autoSize === FloatingAutoSize.Both) {
                        this.style.setProperty('--floating-auto-size-available-height', `${availableHeight}px`);
                    }
                    else {
                        this.style.removeProperty('--floating-auto-size-available-height');
                    }
                    if (this.autoSize === FloatingAutoSize.Horizontal || this.autoSize === FloatingAutoSize.Both) {
                        this.style.setProperty('--floating-auto-size-available-width', `${availableWidth}px`);
                    }
                    else {
                        this.style.removeProperty('--floating-auto-size-available-width');
                    }
                }
            }));
        }
        else {
            // Cleanup styles if we're no longer using auto-size
            this.style.removeProperty('--floating-auto-size-available-width');
            this.style.removeProperty('--floating-auto-size-available-height');
        }
        // Finally, we add an arrow
        if (this.arrow) {
            middleware.push(arrow({
                element: this._arrowElement,
                padding: this.arrowPadding
            }));
        }
        // Use custom positioning logic if the strategy is absolute. Otherwise, fall back to the default logic.
        // More info: https://github.com/shoelace-style/shoelace/issues/1135
        const getOffsetParent = this.strategy === 'absolute'
            ? (element) => 
            // console.warn('### IT USES THE POLIFILL, CHECKIF THIS IS CORRECT');
            platform.getOffsetParent(element)
            : platform.getOffsetParent;
        void computePosition(this._anchorElement, this._bodyElement, {
            placement: this.placement,
            middleware,
            strategy: this.strategy,
            platform: {
                ...platform,
                getOffsetParent
            }
        }).then(({ x, y, middlewareData, placement }) => {
            //
            // Even though we have our own localization utility, it uses different heuristics to determine RTL. Because of
            // that, we'll use the same approach that Floating UI uses.
            //
            // Source: https://github.com/floating-ui/floating-ui/blob/cb3b6ab07f95275730d3e6e46c702f8d4908b55c/packages/dom/src/utils/getDocumentRect.ts#L31
            //
            const isRtl = window.getComputedStyle(this).direction === 'rtl';
            const staticSide = {
                top: 'bottom',
                right: 'left',
                bottom: 'top',
                left: 'right'
            }[placement.split('-')[0]] ?? '';
            this.setAttribute('data-current-placement', placement);
            Object.assign(this._bodyElement.style, {
                left: `${x}px`,
                top: `${y}px`
            });
            if (this.arrow) {
                const arrowX = middlewareData.arrow?.x;
                const arrowY = middlewareData.arrow?.y;
                let top = '';
                let right = '';
                let bottom = '';
                let left = '';
                if (this.arrowPlacement === FloatingArrowPlacement.Start) {
                    const value = typeof arrowX === 'number' ? `calc(${this.arrowPadding}px - var(--floating-arrow-padding-offset))` : '';
                    top = typeof arrowY === 'number' ? `calc(${this.arrowPadding}px - var(--floating-arrow-padding-offset))` : '';
                    right = isRtl ? value : '';
                    left = isRtl ? '' : value;
                }
                else if (this.arrowPlacement === FloatingArrowPlacement.End) {
                    const value = typeof arrowX === 'number' ? `calc(${this.arrowPadding}px - var(--floating-arrow-padding-offset))` : '';
                    right = isRtl ? '' : value;
                    left = isRtl ? value : '';
                    bottom = typeof arrowY === 'number' ? `calc(${this.arrowPadding}px - var(--floating-arrow-padding-offset))` : '';
                }
                else if (this.arrowPlacement === FloatingArrowPlacement.Center) {
                    left = typeof arrowX === 'number' ? 'calc(50% - var(--floating-arrow-size-diagonal))' : '';
                    top = typeof arrowY === 'number' ? 'calc(50% - var(--floating-arrow-size-diagonal))' : '';
                }
                else {
                    // Anchor (default)
                    left = typeof arrowX === 'number' ? `${arrowX}px` : '';
                    top = typeof arrowY === 'number' ? `${arrowY}px` : '';
                }
                Object.assign(this._arrowElement.style, {
                    top,
                    right,
                    bottom,
                    left,
                    [staticSide]: 'calc(var(--floating-arrow-size-diagonal) * -1)'
                });
            }
        });
        this._repositioned.emit();
    }
    /**
     * @public
     */
    getScrollableElement() {
        return this._bodyElement;
    }
    /**
     * @public
     * @override
     */
    connectedCallback() {
        super.connectedCallback();
        // Start the positioner after the first update
        void this.updateComplete.then(() => this.start());
    }
    /**
     * @public
     * @override
     */
    disconnectedCallback() {
        void this.stop();
    }
    /**
     * @protected
     * @override
     */
    onApplyTemplate() {
        super.onApplyTemplate();
        const bodyElement = this.getTemplatePart('body');
        this._bodyElement = bodyElement;
        if (this._arrow) {
            const arrowElement = this.getTemplatePart('arrow');
            this._arrowElement = arrowElement;
        }
    }
    /**
     * @protected
     * @override
     */
    updated(changedProps) {
        super.updated(changedProps);
        // Start or stop the positioner when active changes
        if (changedProps.has('active')) {
            if (this.active) {
                void this.play(fadeIn).then(() => this.start());
            }
            else {
                void this.play(fadeOut).then(() => this.stop());
            }
        }
        // Update the anchor when anchor changes
        if (changedProps.has('anchor')) {
            void this.handleAnchorChange();
        }
        // All other properties will trigger a reposition when active
        if (this.active) {
            void this.updateComplete.then(() => this.reposition());
        }
    }
    /**
     * Emits the {@link repositioned} event.
     *
     * @protected
     */
    onRepositioned(args) {
        this._repositioned.emit(args);
    }
    /**
     * Emits the {@link activeChanged} event.
     *
     * @protected
     */
    onActiveChanged(args) {
        this._activeChanged.emit(args.active);
    }
    onActivePropertyChanged(prev, next) {
        if (prev !== next) {
            this.onActiveChanged(this);
        }
    }
    /**
     * @private
     */
    async handleAnchorChange() {
        await this.stop();
        if (this.anchor && typeof this.anchor === 'string') {
            // Locate the anchor by id
            const root = this.getRootNode();
            this._anchorElement = root.getElementById(this.anchor);
        }
        else if (this.anchor instanceof Element) {
            // Use the anchor's reference
            this._anchorElement = this.anchor;
        }
        else {
            // Look for a slotted anchor
            this._anchorElement = this.querySelector('[slot="anchor"]');
        }
        // If the anchor is a <slot>, we'll use the first assigned element as the target since slots use `display: contents`
        // and positioning can't be calculated on them
        if (this._anchorElement instanceof HTMLSlotElement) {
            this._anchorElement = this._anchorElement.assignedElements({ flatten: true })[0];
        }
        if (!this._anchorElement) {
            throw new Error('Invalid anchor element: no anchor could be found using the anchor slot or the anchor attribute.');
        }
        this.start();
    }
    /**
     * @private
     */
    start() {
        // We can't start the positioner without an anchor
        if (!this._anchorElement) {
            return;
        }
        this._cleanup = autoUpdate(this._anchorElement, this._bodyElement, () => {
            this.reposition();
        });
        // We want to observe clicks on the body.
        this._bodyClickSubscription ??= on(this._bodyElement, 'click', (event) => {
            const clickable = event.composedPath().find((x) => {
                const isElement = x instanceof HTMLElement;
                if (!isElement) {
                    return false;
                }
                // check if any element has the 'force-close' attribute.
                const hasForceClose = x.hasAttribute('force-close');
                const shouldForceClose = hasForceClose && x.getAttribute('force-close') === 'true';
                return shouldForceClose;
            });
            if (clickable) {
                this.active = false;
            }
        });
    }
    /**
     * @private
     */
    async stop() {
        this._bodyClickSubscription?.dispose();
        this._bodyClickSubscription = null;
        return new Promise((resolve) => {
            if (this._cleanup) {
                this._cleanup();
                this._cleanup = undefined;
                this.removeAttribute('data-current-placement');
                this.style.removeProperty('--floating-auto-size-available-width');
                this.style.removeProperty('--floating-auto-size-available-height');
                requestAnimationFrame(resolve);
            }
            else {
                resolve();
            }
        });
    }
};
__decorate([
    QueryChild('[part="arrow"]'),
    __metadata("design:type", HTMLElement)
], FloatingElement.prototype, "_arrowElement", void 0);
__decorate([
    QueryChild('[part="body"]'),
    __metadata("design:type", HTMLElement)
], FloatingElement.prototype, "_bodyElement", void 0);
__decorate([
    Property({ type: Object }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [Object])
], FloatingElement.prototype, "anchor", null);
__decorate([
    Attribute({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], FloatingElement.prototype, "active", null);
__decorate([
    Attribute({ type: Placement }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], FloatingElement.prototype, "placement", null);
__decorate([
    Attribute({ type: String }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], FloatingElement.prototype, "strategy", null);
__decorate([
    Property({ type: Number }),
    __metadata("design:type", Number),
    __metadata("design:paramtypes", [Number])
], FloatingElement.prototype, "distance", null);
__decorate([
    Property({ type: Number }),
    __metadata("design:type", Number),
    __metadata("design:paramtypes", [Number])
], FloatingElement.prototype, "skidding", null);
__decorate([
    Property({ type: Boolean }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], FloatingElement.prototype, "arrow", null);
__decorate([
    Attribute({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], FloatingElement.prototype, "isFullScreen", null);
__decorate([
    Attribute({ type: Number }),
    __metadata("design:type", Number),
    __metadata("design:paramtypes", [Number])
], FloatingElement.prototype, "arrowPadding", null);
__decorate([
    Attribute({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], FloatingElement.prototype, "flip", null);
__decorate([
    Attribute({
        type: (Array),
        attribute: 'flip-fallback-placements',
        converter: {
            fromAttribute: (value) => value.split(' ').map((p) => p.trim())
                .filter((p) => p !== ''),
            toAttribute: (value) => value.join(' ')
        }
    }),
    __metadata("design:type", Array),
    __metadata("design:paramtypes", [Array])
], FloatingElement.prototype, "flipFallbackPlacements", null);
__decorate([
    Attribute({ type: FloatingArrowPlacement }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], FloatingElement.prototype, "arrowPlacement", null);
__decorate([
    Attribute({ type: FloatingFlipFallbackStrategy }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], FloatingElement.prototype, "flipFallbackStrategy", null);
__decorate([
    Property({ type: Object }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [Object])
], FloatingElement.prototype, "flipBoundary", null);
__decorate([
    Attribute({ type: Number }),
    __metadata("design:type", Number),
    __metadata("design:paramtypes", [Number])
], FloatingElement.prototype, "flipPadding", null);
__decorate([
    Attribute({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], FloatingElement.prototype, "shift", null);
__decorate([
    Property({ type: Object }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [Object])
], FloatingElement.prototype, "shiftBoundary", null);
__decorate([
    Attribute({ type: Number }),
    __metadata("design:type", Number),
    __metadata("design:paramtypes", [Number])
], FloatingElement.prototype, "shiftPadding", null);
__decorate([
    Attribute({ type: FloatingAutoSize }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], FloatingElement.prototype, "autoSize", null);
__decorate([
    Attribute({ type: FloatingSync }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], FloatingElement.prototype, "sync", null);
__decorate([
    Property({ type: Object }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [Object])
], FloatingElement.prototype, "autoSizeBoundary", null);
__decorate([
    Attribute({ type: Number }),
    __metadata("design:type", Number),
    __metadata("design:paramtypes", [Number])
], FloatingElement.prototype, "autoSizePadding", null);
__decorate([
    Attribute({
        type: String,
        converter: {
            toAttribute: (value) => typeof value === 'number' ? `${value}px` : value?.toString() ?? ''
        }
    }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [Object])
], FloatingElement.prototype, "maxWidth", null);
__decorate([
    Attribute({
        type: String,
        converter: {
            toAttribute: (value) => typeof value === 'number' ? `${value}px` : value?.toString() ?? ''
        }
    }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [Object])
], FloatingElement.prototype, "maxHeight", null);
__decorate([
    Emit({ eventName: 'repositioned' }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [])
], FloatingElement.prototype, "repositioned", null);
__decorate([
    Emit({ eventName: 'activeChanged' }),
    __metadata("design:type", Object),
    __metadata("design:paramtypes", [])
], FloatingElement.prototype, "activeChanged", null);
__decorate([
    Watch('active'),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Boolean, Boolean]),
    __metadata("design:returntype", void 0)
], FloatingElement.prototype, "onActivePropertyChanged", null);
FloatingElement = __decorate([
    Component({
        selector: 'mosaik-floating',
        template: floatingElementTemplate,
        themes: {
            joy: floatingElementJoyStyle,
            retro: floatingElementRetroStyle,
            cosmopolitan: floatingElementCosmopolitanStyle
        },
        imports: [
            ElevationElement
        ]
    }),
    __metadata("design:paramtypes", [])
], FloatingElement);
export { FloatingElement };
//# sourceMappingURL=FloatingElement.js.map