// #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 { on } from '@breadstone/mosaik-elements';
import { Attachable } from '../../../Behaviors/Attachable';
import { Disableable } from '../../../Behaviors/Disableable';
import { TextFormattable } from '../../../Behaviors/TextFormattable';
import { Attribute } from '../../../Decorators/AttributeDecorator';
import { Component } from '../../../Decorators/ComponentDecorator';
import { QueryChild } from '../../../Decorators/QueryChildDecorator';
import { Watch } from '../../../Decorators/WatchDecorator';
import { Placement } from '../../../Types/Placement';
import { Trigger } from '../../../Types/Trigger';
import { CustomElement } from '../../Abstracts/CustomElement';
import { FloatingElement } from '../Floating/FloatingElement';
import { TextElement } from '../Text/TextElement';
import { tooltipElementTemplate } from './TooltipElementTemplate';
import { Openable } from '../../../Behaviors/Openable';
import { Closeable } from '../../../Behaviors/Closeable';
import { tooltipElementJoyStyle } from './Themes/TooltipElement.Joy';
import { tooltipElementRetroStyle } from './Themes/TooltipElement.Retro';
import { tooltipElementCosmopolitanStyle } from './Themes/TooltipElement.Cosmopolitan';
import { Themeable } from '../../../Behaviors/Themeable';
import { PortalElement } from '../Portal/PortalElement';
import { Slottable } from '../../../Behaviors/Slottable';
// #endregion
/**
 * Tooltip - A brief, contextual description that appears when hovering over an element.
 *
 * @element mosaik-tooltip
 *
 * @fires opened - Called when the tooltip is opened.
 * @fires closed - Called when the tooltip is closed.
 *
 * @public
 */
let TooltipElement = class TooltipElement extends Themeable(Attachable(Disableable(TextFormattable(Openable(Closeable(Slottable(CustomElement))))))) {
    // #region Fields
    _body;
    _popup;
    _content;
    _placement;
    _horizontalOffset;
    _verticalOffset;
    _isOpen;
    _showDelay;
    _hideDelay;
    _trigger;
    _staysOpen;
    _hoverTimeout;
    _blurSubscription;
    _focusSubscription;
    _clickSubscription;
    _keydownSubscription;
    _mouseoutSubscription;
    // #endregion
    // #region Ctor
    /**
     * @public
     */
    constructor() {
        super();
        this._content = '';
        this._placement = Placement.Bottom;
        this._horizontalOffset = 8;
        this._verticalOffset = 0;
        this._isOpen = false;
        this._showDelay = 150; // material is 300
        this._hideDelay = 0; // material is 100
        this._trigger = Trigger.Hover;
        this._staysOpen = false;
        this._hoverTimeout = null;
        this._blurSubscription = null;
        this._focusSubscription = null;
        this._clickSubscription = null;
        this._keydownSubscription = null;
        this._mouseoutSubscription = null;
    }
    // #endregion
    // #region Properties
    /**
     * Returns the `is` property.
     *
     * @public
     * @static
     * @readonly
    */
    static get is() {
        return 'mosaik-tooltip';
    }
    /**
     * Gets or sets the `content` property.
     *
     * @public
     * @attr
     */
    get content() {
        return this._content;
    }
    set content(value) {
        if (this._content !== value) {
            this._content = value;
            this.requestUpdate('content');
        }
    }
    /**
     * Gets or sets the `placement` property.
     *
     * @public
     * @attr
     */
    get placement() {
        return this._placement;
    }
    set placement(value) {
        if (this._placement !== value) {
            this._placement = value;
            this.requestUpdate('placement');
        }
    }
    /**
     * Gets or sets the `horizontalOffset` property.
     *
     * @public
     * @attr
     */
    get horizontalOffset() {
        return this._horizontalOffset;
    }
    set horizontalOffset(value) {
        if (this._horizontalOffset !== value) {
            this._horizontalOffset = value;
            this.requestUpdate('horizontalOffset');
        }
    }
    /**
     * Gets or sets the `verticalOffset` property.
     *
     * @public
     * @attr
     */
    get verticalOffset() {
        return this._verticalOffset;
    }
    set verticalOffset(value) {
        if (this._verticalOffset !== value) {
            this._verticalOffset = value;
            this.requestUpdate('verticalOffset');
        }
    }
    /**
     * Gets or sets the `isOpen` property.
     *
     * @public
     * @attr
     */
    get isOpen() {
        return this._isOpen;
    }
    set isOpen(value) {
        if (this._isOpen !== value) {
            this._isOpen = value;
            this.requestUpdate('isOpen');
        }
    }
    /**
     * Gets or sets the `showDelay` property.
     *
     * @public
     * @attr
     */
    get showDelay() {
        return this._showDelay;
    }
    set showDelay(value) {
        if (this._showDelay !== value) {
            this._showDelay = value;
            this.requestUpdate('showDelay');
        }
    }
    /**
     * Gets or sets the `hideDelay` property.
     *
     * @public
     * @attr
     */
    get hideDelay() {
        return this._hideDelay;
    }
    set hideDelay(value) {
        if (this._hideDelay !== value) {
            this._hideDelay = value;
            this.requestUpdate('hideDelay');
        }
    }
    /**
     * Gets or sets the `trigger` property.
     *
     * @public
     * @attr
     */
    get trigger() {
        return this._trigger;
    }
    set trigger(value) {
        if (this._trigger !== value) {
            this._trigger = value;
            this.requestUpdate('trigger');
        }
    }
    /**
     * Gets or sets the `staysOpen` property.
     *
     * @public
     * @attr
     */
    get staysOpen() {
        return this._staysOpen;
    }
    set staysOpen(value) {
        if (this._staysOpen !== value) {
            this._staysOpen = value;
            this.requestUpdate('staysOpen');
        }
    }
    // #endregion
    // #region Methods
    /**
     * Opens the tooltip.
     *
     * @public
     * @override
     */
    async open() {
        await super.open()
            .then(() => {
            this.isOpen = true;
        });
    }
    /**
     * Closes the tooltip.
     *
     * @public
     * @override
     */
    async close() {
        if (this._staysOpen) {
            return Promise.resolve(false);
        }
        if (!this._isOpen) {
            return Promise.resolve(true);
        }
        return super.close().then((x) => this.isOpen = x);
    }
    /**
     * @public
     * @override
     */
    attach(control) {
        super.attach(control);
        void this.updateComplete.then(() => {
            this._popup.anchor = control;
        });
    }
    /**
     * @public
     * @override
     */
    connectedCallback() {
        super.connectedCallback();
        if (this.control) {
            this._blurSubscription = on(this.control, 'blur', (e) => this.onBlur(e), true);
            this._focusSubscription = on(this.control, 'focus', (e) => this.onFocus(e), true);
            this._clickSubscription = on(this.control, 'click', (e) => this.onClick(e));
            this._keydownSubscription = on(this.control, 'keydown', (e) => this.onKeyDown(e));
            this._mouseoutSubscription = on(this.control, 'mouseover', (e) => this.onMouseOver(e));
            this._mouseoutSubscription = on(this.control, 'mouseout', (e) => this.onMouseOut(e));
        }
    }
    /**
     * @public
     * @override
     */
    disconnectedCallback() {
        super.disconnectedCallback();
        this._blurSubscription?.dispose();
        this._focusSubscription?.dispose();
        this._clickSubscription?.dispose();
        this._keydownSubscription?.dispose();
        this._mouseoutSubscription?.dispose();
    }
    /**
    * @protected
    * @override
    */
    onApplyTemplate() {
        super.onApplyTemplate();
        const bodyElement = this.getTemplatePart('body');
        this._body = bodyElement;
        const popupElement = this.getTemplatePart('popup');
        this._popup = popupElement;
    }
    /**
     * @protected
     * @override
     */
    firstUpdated(changedProperties) {
        super.firstUpdated(changedProperties);
        this._body.hidden = !this.isOpen;
        // If the tooltip is visible on init, update its position
        if (this.isOpen) {
            this._popup.active = true;
            this._popup.reposition();
        }
    }
    /**
     * @protected
     */
    onBlur(_event) {
        if (this.hasTrigger(Trigger.Focus)) {
            void this.close();
        }
    }
    /**
     * @protected
     */
    onClick(_event) {
        if (this.hasTrigger(Trigger.Click)) {
            if (this.isOpen) {
                void this.close();
            }
            else {
                void this.open();
            }
        }
    }
    /**
     * @protected
     */
    onFocus(_event) {
        if (this.hasTrigger(Trigger.Focus)) {
            void this.open();
        }
    }
    /**
     * @protected
     */
    onKeyDown(event) {
        // Pressing escape when the target element has focus should dismiss the tooltip
        if (this.isOpen && event.key === 'Escape') {
            event.stopPropagation();
            void this.close();
        }
    }
    /**
     * @protected
     */
    onMouseOver(_event) {
        if (this.hasTrigger(Trigger.Hover)) {
            if (this._hoverTimeout) {
                clearTimeout(this._hoverTimeout);
            }
            this._hoverTimeout = window.setTimeout(() => void this.open(), this._showDelay);
        }
    }
    /**
     * @protected
     */
    onMouseOut(_event) {
        if (this.hasTrigger(Trigger.Hover)) {
            if (this._hoverTimeout) {
                clearTimeout(this._hoverTimeout);
            }
            this._hoverTimeout = window.setTimeout(() => void this.close(), this._hideDelay);
        }
    }
    /**
     * @protected
     */
    onIsOpenPropertyChange() {
        void this.updateComplete.then(() => {
            if (this.isOpen) {
                if (this.disabled) {
                    return;
                }
                this.opened.emit();
                // await stopAnimations(this._body);
                this._body.hidden = false;
                this._popup.active = true;
                // const { keyframes, options } = getAnimation(this, 'tooltip.show', { dir: this.dir });
                // await animateTo(this._popup.popup, keyframes, options);
            }
            else {
                // Hide
                // this.emit('sl-hide');
                const args = { cancel: false };
                this.closed.emit(args);
                if (!args.cancel) {
                    //  await stopAnimations(this._body);
                    //  const { keyframes, options } = getAnimation(this, 'tooltip.hide', { dir: this.localize.dir() });
                    //  await animateTo(this._popup.popup, keyframes, options);
                    this._popup.active = false;
                    this._body.hidden = true;
                }
            }
        });
    }
    /**
     * @protected
     */
    onContentPropertyChange(_oldValue, newValue) {
        this._content = this.formatter
            ? this.formatter(newValue)
            : newValue;
        void this.updateComplete.then(() => this._popup.reposition());
    }
    /**
     * @protected
     */
    onDistancePropertyChange() {
        void this.updateComplete.then(() => {
            this._popup.reposition();
        });
    }
    /**
     * @protected
     */
    onPlacementPropertyChange() {
        void this.updateComplete.then(() => {
            this._popup.reposition();
        });
    }
    /**
     * @protected
     */
    onSkiddingPropertyChange() {
        void this.updateComplete.then(() => {
            this._popup.reposition();
        });
    }
    /**
     * @protected
     */
    onDisabledPropertyChange() {
        if (this.disabled && this.isOpen) {
            void this.close();
        }
    }
    /**
     * @private
     */
    hasTrigger(triggerType) {
        const triggers = this.trigger.split(' ');
        return triggers.includes(triggerType);
    }
};
__decorate([
    QueryChild('[part="body"]'),
    __metadata("design:type", HTMLElement)
], TooltipElement.prototype, "_body", void 0);
__decorate([
    QueryChild('[part="popup"]'),
    __metadata("design:type", FloatingElement)
], TooltipElement.prototype, "_popup", void 0);
__decorate([
    Attribute({ type: String }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], TooltipElement.prototype, "content", null);
__decorate([
    Attribute({ type: Placement }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], TooltipElement.prototype, "placement", null);
__decorate([
    Attribute({ type: Number }),
    __metadata("design:type", Number),
    __metadata("design:paramtypes", [Number])
], TooltipElement.prototype, "horizontalOffset", null);
__decorate([
    Attribute({ type: Number }),
    __metadata("design:type", Number),
    __metadata("design:paramtypes", [Number])
], TooltipElement.prototype, "verticalOffset", null);
__decorate([
    Attribute({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], TooltipElement.prototype, "isOpen", null);
__decorate([
    Attribute({ type: Number }),
    __metadata("design:type", Number),
    __metadata("design:paramtypes", [Number])
], TooltipElement.prototype, "showDelay", null);
__decorate([
    Attribute({ type: Number }),
    __metadata("design:type", Number),
    __metadata("design:paramtypes", [Number])
], TooltipElement.prototype, "hideDelay", null);
__decorate([
    Attribute({ type: Trigger }),
    __metadata("design:type", String),
    __metadata("design:paramtypes", [String])
], TooltipElement.prototype, "trigger", null);
__decorate([
    Attribute({
        type: Boolean,
        useDefault: true
    }),
    __metadata("design:type", Boolean),
    __metadata("design:paramtypes", [Boolean])
], TooltipElement.prototype, "staysOpen", null);
__decorate([
    Watch('isOpen', { waitUntilFirstUpdate: true }),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", []),
    __metadata("design:returntype", void 0)
], TooltipElement.prototype, "onIsOpenPropertyChange", null);
__decorate([
    Watch('content'),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String, String]),
    __metadata("design:returntype", void 0)
], TooltipElement.prototype, "onContentPropertyChange", null);
__decorate([
    Watch('distance'),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", []),
    __metadata("design:returntype", void 0)
], TooltipElement.prototype, "onDistancePropertyChange", null);
__decorate([
    Watch('placement'),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", []),
    __metadata("design:returntype", void 0)
], TooltipElement.prototype, "onPlacementPropertyChange", null);
__decorate([
    Watch('skidding'),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", []),
    __metadata("design:returntype", void 0)
], TooltipElement.prototype, "onSkiddingPropertyChange", null);
__decorate([
    Watch('disabled'),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", []),
    __metadata("design:returntype", void 0)
], TooltipElement.prototype, "onDisabledPropertyChange", null);
TooltipElement = __decorate([
    Component({
        selector: 'mosaik-tooltip',
        template: tooltipElementTemplate,
        themes: {
            joy: tooltipElementJoyStyle,
            retro: tooltipElementRetroStyle,
            cosmopolitan: tooltipElementCosmopolitanStyle
        },
        imports: [
            TextElement,
            PortalElement,
            FloatingElement
        ]
    }),
    __metadata("design:paramtypes", [])
], TooltipElement);
export { TooltipElement };
//# sourceMappingURL=TooltipElement.js.map