/**
 * Copyright Aquera Inc 2023
 *
 * This source code is licensed under the BSD-3-Clause license found in the
 * LICENSE file in the root directory of this source tree.
 */
import { __decorate } from "tslib";
import { styles } from './nile-tooltip.css';
import '../nile-popup/nile-popup';
import { animateTo, parseDuration, stopAnimations } from '../internal/animate';
import { classMap } from 'lit/directives/class-map.js';
import { customElement, property, query } from 'lit/decorators.js';
import { getAnimation, setDefaultAnimation, } from '../utilities/animation-registry';
import { html } from 'lit';
// import { LocalizeController } from '../utilities/localize';
import { waitForEvent } from '../internal/event';
import { watch } from '../internal/watch';
import NileElement from '../internal/nile-element';
import { VisibilityManager } from '../utilities/visibility-manager.js';
/**
 * Nile icon component.
 *
 * @tag nile-tooltip
 *
 */
let NileTooltip = class NileTooltip extends NileElement {
    constructor() {
        super(...arguments);
        /** The tooltip's content. If you need to display HTML, use the `content` slot instead. */
        this.content = '';
        /** Size Property to decide the tool tip size */
        this.size = 'small';
        /**
         * The preferred placement of the tooltip. Note that the actual placement may vary as needed to keep the tooltip
         * inside of the viewport.
         */
        this.placement = 'top';
        /** Disables the tooltip so it won't show when triggered. */
        this.disabled = false;
        /** The distance in pixels from which to offset the tooltip away from its target. */
        this.distance = 8;
        /** Indicates whether or not the tooltip is open. You can use this in lieu of the show/hide methods. */
        this.open = false;
        /** The distance in pixels from which to offset the tooltip along its target. */
        this.skidding = 0;
        /**
         * Controls how the tooltip is activated. Possible options include `click`, `hover`, `focus`, and `manual`. Multiple
         * options can be passed by separating them with a space. When manual is used, the tooltip must be activated
         * programmatically.
         */
        this.trigger = 'hover focus';
        /**
         * Enable this option to prevent the tooltip from being clipped when the component is placed inside a container with
         * `overflow: auto|hidden|scroll`. Hoisting uses a fixed positioning strategy that works in many, but not all,
         * scenarios.
         */
        this.hoist = false;
        this.enableVisibilityEffect = false;
        this.enableTabClose = false;
    }
    /**
     * The styles for Tooltip
     * @remarks If you are extending this class you can extend the base styles with super. Eg `return [super(), myCustomStyles]`
     */
    static get styles() {
        return [styles];
    }
    connectedCallback() {
        super.connectedCallback();
        this.handleBlur = this.handleBlur.bind(this);
        this.handleClick = this.handleClick.bind(this);
        this.handleFocus = this.handleFocus.bind(this);
        this.handleKeyDown = this.handleKeyDown.bind(this);
        this.handleMouseOver = this.handleMouseOver.bind(this);
        this.handleMouseOut = this.handleMouseOut.bind(this);
        this.updateComplete.then(() => {
            this.addEventListener('blur', this.handleBlur, true);
            this.addEventListener('focus', this.handleFocus, true);
            this.addEventListener('click', this.handleClick);
            this.addEventListener('keydown', this.handleKeyDown);
            this.addEventListener('mouseover', this.handleMouseOver);
            this.addEventListener('mouseout', this.handleMouseOut);
        });
    }
    firstUpdated() {
        this.body.hidden = !this.open;
        // If the tooltip is visible on init, update its position
        if (this.open) {
            this.popup.active = true;
            this.popup.reposition();
        }
        const anchorSlot = this.renderRoot.querySelector('slot:not([name])');
        const anchorEl = anchorSlot?.assignedElements({ flatten: true })[0];
        this.visibilityManager = new VisibilityManager({
            host: this,
            target: anchorEl || null,
            enableVisibilityEffect: this.enableVisibilityEffect,
            enableTabClose: this.enableTabClose,
            isOpen: () => this.open,
            onAnchorOutOfView: () => {
                this.hide();
                this.emit('nile-visibility-change', {
                    visible: false,
                    reason: 'anchor-out-of-view',
                });
            },
            onDocumentHidden: () => {
                this.hide();
                this.emit('nile-visibility-change', {
                    visible: false,
                    reason: 'document-hidden',
                });
            },
            emit: (event, detail) => this.emit(`nile-${event}`, detail),
        });
    }
    disconnectedCallback() {
        super.disconnectedCallback();
        this.visibilityManager?.cleanup();
        this.removeEventListener('blur', this.handleBlur, true);
        this.removeEventListener('focus', this.handleFocus, true);
        this.removeEventListener('click', this.handleClick);
        this.removeEventListener('keydown', this.handleKeyDown);
        this.removeEventListener('mouseover', this.handleMouseOver);
        this.removeEventListener('mouseout', this.handleMouseOut);
    }
    handleBlur() {
        if (this.hasTrigger('focus')) {
            this.hide();
        }
    }
    handleClick() {
        if (this.hasTrigger('click')) {
            if (this.open) {
                this.hide();
            }
            else {
                this.show();
            }
        }
    }
    handleFocus() {
        if (this.hasTrigger('focus')) {
            this.show();
        }
    }
    handleKeyDown(event) {
        // Pressing escape when the target element has focus should dismiss the tooltip
        if (this.open && event.key === 'Escape') {
            event.stopPropagation();
            this.hide();
        }
    }
    handleMouseOver() {
        if (this.hasTrigger('hover')) {
            const delay = parseDuration(getComputedStyle(this).getPropertyValue('--show-delay'));
            clearTimeout(this.hoverTimeout);
            this.hoverTimeout = window.setTimeout(() => this.show(), delay);
        }
    }
    handleMouseOut() {
        if (this.hasTrigger('hover')) {
            const delay = parseDuration(getComputedStyle(this).getPropertyValue('--hide-delay'));
            clearTimeout(this.hoverTimeout);
            this.hoverTimeout = window.setTimeout(() => this.hide(), delay);
        }
    }
    hasTrigger(triggerType) {
        const triggers = this.trigger.split(' ');
        return triggers.includes(triggerType);
    }
    async handleOpenChange() {
        if (this.open) {
            this.visibilityManager?.setup();
            if (this.disabled) {
                return;
            }
            // Show
            this.emit('nile-show');
            await stopAnimations(this.body);
            this.body.hidden = false;
            this.popup.active = true;
            const { keyframes, options } = getAnimation(this, 'tooltip.show', {
                dir: '',
            });
            await animateTo(this.popup.popup, keyframes, options);
            this.emit('nile-after-show');
        }
        else {
            this.visibilityManager?.cleanup();
            // Hide
            this.emit('nile-hide');
            await stopAnimations(this.body);
            const { keyframes, options } = getAnimation(this, 'tooltip.hide', {
                dir: '',
            });
            await animateTo(this.popup.popup, keyframes, options);
            this.popup.active = false;
            this.body.hidden = true;
            this.emit('nile-after-hide');
        }
    }
    async handleOptionsChange() {
        if (this.hasUpdated) {
            await this.updateComplete;
            this.popup.reposition();
        }
    }
    handleDisabledChange() {
        if (this.disabled && this.open) {
            this.hide();
        }
    }
    /** Shows the tooltip. */
    async show() {
        if (this.open || !this.content?.trim().length) {
            return undefined;
        }
        this.open = true;
        return waitForEvent(this, 'nile-after-show');
    }
    /** Hides the tooltip */
    async hide() {
        if (!this.open) {
            return undefined;
        }
        this.open = false;
        return waitForEvent(this, 'nile-after-hide');
    }
    render() {
        return html `
      <nile-popup
        part="base"
        exportparts="
          popup:base__popup,
          arrow:base__arrow
        "
        class=${classMap({
            tooltip: true,
            'tooltip--open': this.open,
        })}
        placement=${this.placement}
        distance=${this.distance}
        skidding=${this.skidding}
        strategy=${this.hoist ? 'fixed' : 'absolute'}
        flip
        shift
        arrow
      >
        <slot slot="anchor" aria-describedby="tooltip"></slot>

        <slot
          name="content"
          part="body"
          id="tooltip"
          class=${classMap({
            tooltip__body: true,
            'tooltip__body--large': this.size === 'large',
        })}
          role="tooltip"
          aria-live=${this.open ? 'polite' : 'off'}
        >
          ${this.content}
        </slot>
      </nile-popup>
    `;
    }
};
__decorate([
    query('slot:not([name])')
], NileTooltip.prototype, "defaultSlot", void 0);
__decorate([
    query('.tooltip__body')
], NileTooltip.prototype, "body", void 0);
__decorate([
    query('nile-popup')
], NileTooltip.prototype, "popup", void 0);
__decorate([
    property({ type: String, reflect: true })
], NileTooltip.prototype, "content", void 0);
__decorate([
    property({ reflect: true })
], NileTooltip.prototype, "size", void 0);
__decorate([
    property()
], NileTooltip.prototype, "placement", void 0);
__decorate([
    property({ type: Boolean, reflect: true })
], NileTooltip.prototype, "disabled", void 0);
__decorate([
    property({ type: Number })
], NileTooltip.prototype, "distance", void 0);
__decorate([
    property({ type: Boolean, reflect: true })
], NileTooltip.prototype, "open", void 0);
__decorate([
    property({ type: Number })
], NileTooltip.prototype, "skidding", void 0);
__decorate([
    property()
], NileTooltip.prototype, "trigger", void 0);
__decorate([
    property({ type: Boolean })
], NileTooltip.prototype, "hoist", void 0);
__decorate([
    property({ type: Boolean, reflect: true })
], NileTooltip.prototype, "enableVisibilityEffect", void 0);
__decorate([
    property({ type: Boolean, reflect: true })
], NileTooltip.prototype, "enableTabClose", void 0);
__decorate([
    watch('open', { waitUntilFirstUpdate: true })
], NileTooltip.prototype, "handleOpenChange", null);
__decorate([
    watch(['content', 'distance', 'hoist', 'placement', 'skidding'])
], NileTooltip.prototype, "handleOptionsChange", null);
__decorate([
    watch('disabled')
], NileTooltip.prototype, "handleDisabledChange", null);
NileTooltip = __decorate([
    customElement('nile-tooltip')
], NileTooltip);
export { NileTooltip };
setDefaultAnimation('tooltip.show', {
    keyframes: [
        { opacity: 0, scale: 0.8 },
        { opacity: 1, scale: 1 },
    ],
    options: { duration: 150, easing: 'ease' },
});
setDefaultAnimation('tooltip.hide', {
    keyframes: [
        { opacity: 1, scale: 1 },
        { opacity: 0, scale: 0.8 },
    ],
    options: { duration: 150, easing: 'ease' },
});
export default NileTooltip;
//# sourceMappingURL=nile-tooltip.js.map