/*!
 * Custom elements for Nanopore-Digital Web applications
 */
import { Host, } from "@stencil/core";
import { h } from "../../utils/renderer";
import Popover from "../../utils/popover";
/**
 * Tooltips display additional information based on a specific action.
 *
 * @version 1.0.0
 * @status stable
 *
 * @slot - The tooltip's target element. Only the first element will be used as the target.
 * @slot content - The tooltip's content. Alternatively, you can use the content prop.
 */
export class Tooltip {
    isVisible = false;
    popover;
    tooltipPositioner;
    tooltip;
    _target;
    get target() {
        return this._target;
    }
    set target(newTarget) {
        if (newTarget !== this._target && this._target) {
            this._target.removeAttribute('aria-label');
        }
        newTarget.setAttribute('aria-label', this.label);
        this._target = newTarget;
    }
    label = '';
    host;
    /** The tooltip's content. Alternatively, you can use the content slot. */
    content = '';
    setLabel() {
        const contentSlotNodes = Array.from(this.host.querySelectorAll('[slot="content"]'));
        const textContent = contentSlotNodes
            .map((node) => node.textContent)
            .join(' ')
            .trim();
        if (!this.target) {
            this.target = this.getTarget();
            if (!this.target)
                return;
        }
        this.label = textContent || this.content;
        this.target.setAttribute('aria-label', this.label);
    }
    /**
     * The preferred placement of the tooltip. Note that the actual placement may vary as needed to keep the tooltip
     * inside of the viewport.
     */
    placement = 'top';
    /** Set to true to disable the tooltip so it won't show when triggered. */
    disabled = false;
    /** The distance in pixels from which to offset the tooltip away from its target. */
    distance = 10;
    /** Indicates whether or not the tooltip is open. You can use this in lieu of the show/hide methods. */
    open = false;
    /** The distance in pixels from which to offset the tooltip along its target. */
    skidding = 0;
    /**
     * Enable this option to prevent the panel from being clipped when the component is placed inside a container with
     * `overflow: auto|scroll`.
     */
    hoist = false;
    /**
     * 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.
     */
    trigger = 'hover focus';
    handleOpenChange() {
        if (this.open)
            this.show();
        else
            this.hide();
    }
    // Events
    /** Emitted when the tooltip begins to show. Calling `event.preventDefault()` will prevent it from being shown. */
    nanoShow;
    /** Emitted after the tooltip has shown and all transitions are complete. */
    nanoAfterShow;
    /** Emitted when the tooltip begins to hide. Calling `event.preventDefault()` will prevent it from being hidden. */
    nanoHide;
    /** Emitted after the tooltip has hidden and all transitions are complete. */
    nanoAfterHide;
    // Public methods
    /** Shows the tooltip. */
    async show() {
        // Prevent subsequent calls to the method, whether manually or triggered by the `open` watcher
        if (this.isVisible || this.disabled) {
            return;
        }
        const slShow = this.nanoShow.emit();
        if (slShow.defaultPrevented) {
            this.open = false;
            return;
        }
        this.isVisible = true;
        this.open = true;
        if (typeof this.tooltipPositioner?.showPopover === 'function') {
            this.hoist = true;
            this.popover.show();
            this.tooltipPositioner.showPopover();
        }
        else {
            this.popover.show();
        }
    }
    /** Hides the tooltip. */
    async hide() {
        // Prevent subsequent calls to the method, whether manually or triggered by the `open` watcher
        if (!this.isVisible) {
            return;
        }
        const slHide = this.nanoHide.emit();
        if (slHide.defaultPrevented) {
            this.open = true;
            return;
        }
        this.isVisible = false;
        this.open = false;
        this.popover.hide();
        setTimeout(() => {
            if (!this.open &&
                typeof this.tooltipPositioner?.hidePopover === 'function') {
                this.tooltipPositioner.hidePopover();
            }
        }, 300);
    }
    // Private methods
    getTarget() {
        let children = Array.from(this.host.children);
        // add display contents children
        children = children.flatMap((el) => {
            const display = getComputedStyle(el).display;
            if (display === 'none')
                return [];
            if (display === 'contents' && el.children?.length) {
                return Array.from(el.children);
            }
            return el;
        });
        // Get the first child that isn't a <style> or content slot
        const target = children.find((el) => el.tagName.toLowerCase() !== 'style' &&
            el.getAttribute('slot') !== 'content');
        if (!target) {
            throw new Error('Invalid tooltip target: no child element was found.');
        }
        return target;
    }
    hasTrigger(triggerType) {
        const triggers = this.trigger.split(' ');
        return triggers.includes(triggerType);
    }
    syncOptions() {
        this.popover.setOptions({
            strategy: this.hoist ? 'fixed' : 'absolute',
            placement: this.placement,
            distance: this.distance,
            skidding: this.skidding,
            transitionElement: this.tooltip,
            onAfterHide: () => this.nanoAfterHide.emit(),
            onAfterShow: () => this.nanoAfterShow.emit(),
        });
    }
    // Event Handlers
    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')) {
            this.show();
        }
    };
    handleMouseOut = () => {
        if (this.hasTrigger('hover')) {
            this.hide();
        }
    };
    handleSlotChange = () => {
        this.target = this.getTarget();
    };
    // Stencil hooks
    componentDidLoad() {
        this.target = this.getTarget();
        this.popover = new Popover(this.target, this.tooltipPositioner, {
            sameWidth: false,
        });
        this.syncOptions();
        this.setLabel();
        // Show on init if open
        this.tooltipPositioner.hidden = !this.open;
        if (this.open) {
            this.show();
        }
    }
    componentDidUpdate() {
        this.syncOptions();
    }
    disconnectedCallback() {
        if (this.popover)
            this.popover.destroy();
    }
    render() {
        return (h(Host, { key: '79951f5782653b519fabd8345c2ec0af5cf86f2d', onKeyDown: this.handleKeyDown, onMouseOver: this.handleMouseOver, onMouseOut: this.handleMouseOut, onBlur: this.handleBlur, onFocus: this.handleFocus, onClick: this.handleClick, class: "nano-tooltip" }, h("slot", { key: '6698cb226357c92807393c1fe2f73991c13ead07', onSlotchange: this.handleSlotChange }), h("div", { key: 'dbb8bda886e15850c17c06dca8d9f8924cb62486', ref: (el) => (this.tooltipPositioner = el), class: "tooltip-positioner", popover: "manual" }, h("div", { key: '9b1f5692d592331470c0159229aab8fbcb091b21', part: "base", ref: (el) => (this.tooltip = el), class: {
                tooltip: true,
                'tooltip--open': this.open,
            }, role: "tooltip", "aria-hidden": this.open ? 'false' : 'true' }, h("slot", { key: '1e6f35227072b696e2cea3cbf93eea26285b20cf', name: "content", onSlotchange: () => this.setLabel() }, this.content), h("div", { key: 'dab2de407dae223b4ac229283d9dedb8a69e4919', class: "tooltip-arrow", "data-popper-arrow": true })))));
    }
    static get is() { return "nano-tooltip"; }
    static get encapsulation() { return "shadow"; }
    static get originalStyleUrls() {
        return {
            "$": ["tooltip.scss"]
        };
    }
    static get styleUrls() {
        return {
            "$": ["tooltip.css"]
        };
    }
    static get properties() {
        return {
            "content": {
                "type": "string",
                "attribute": "content",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "The tooltip's content. Alternatively, you can use the content slot."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "defaultValue": "''"
            },
            "placement": {
                "type": "string",
                "attribute": "placement",
                "mutable": false,
                "complexType": {
                    "original": "| 'top'\n    | 'top-start'\n    | 'top-end'\n    | 'right'\n    | 'right-start'\n    | 'right-end'\n    | 'bottom'\n    | 'bottom-start'\n    | 'bottom-end'\n    | 'left'\n    | 'left-start'\n    | 'left-end'",
                    "resolved": "\"bottom\" | \"bottom-end\" | \"bottom-start\" | \"left\" | \"left-end\" | \"left-start\" | \"right\" | \"right-end\" | \"right-start\" | \"top\" | \"top-end\" | \"top-start\"",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "The preferred placement of the tooltip. Note that the actual placement may vary as needed to keep the tooltip\ninside of the viewport."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "defaultValue": "'top'"
            },
            "disabled": {
                "type": "boolean",
                "attribute": "disabled",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Set to true to disable the tooltip so it won't show when triggered."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "defaultValue": "false"
            },
            "distance": {
                "type": "number",
                "attribute": "distance",
                "mutable": false,
                "complexType": {
                    "original": "number",
                    "resolved": "number",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "The distance in pixels from which to offset the tooltip away from its target."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "defaultValue": "10"
            },
            "open": {
                "type": "boolean",
                "attribute": "open",
                "mutable": true,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Indicates whether or not the tooltip is open. You can use this in lieu of the show/hide methods."
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "defaultValue": "false"
            },
            "skidding": {
                "type": "number",
                "attribute": "skidding",
                "mutable": false,
                "complexType": {
                    "original": "number",
                    "resolved": "number",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "The distance in pixels from which to offset the tooltip along its target."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "defaultValue": "0"
            },
            "hoist": {
                "type": "boolean",
                "attribute": "hoist",
                "mutable": true,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Enable this option to prevent the panel from being clipped when the component is placed inside a container with\n`overflow: auto|scroll`."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "defaultValue": "false"
            },
            "trigger": {
                "type": "string",
                "attribute": "trigger",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Controls how the tooltip is activated. Possible options include `click`, `hover`, `focus`, and `manual`. Multiple\noptions can be passed by separating them with a space. When manual is used, the tooltip must be activated\nprogrammatically."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "defaultValue": "'hover focus'"
            }
        };
    }
    static get events() {
        return [{
                "method": "nanoShow",
                "name": "nanoShow",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Emitted when the tooltip begins to show. Calling `event.preventDefault()` will prevent it from being shown."
                },
                "complexType": {
                    "original": "any",
                    "resolved": "any",
                    "references": {}
                }
            }, {
                "method": "nanoAfterShow",
                "name": "nanoAfterShow",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Emitted after the tooltip has shown and all transitions are complete."
                },
                "complexType": {
                    "original": "any",
                    "resolved": "any",
                    "references": {}
                }
            }, {
                "method": "nanoHide",
                "name": "nanoHide",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Emitted when the tooltip begins to hide. Calling `event.preventDefault()` will prevent it from being hidden."
                },
                "complexType": {
                    "original": "any",
                    "resolved": "any",
                    "references": {}
                }
            }, {
                "method": "nanoAfterHide",
                "name": "nanoAfterHide",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Emitted after the tooltip has hidden and all transitions are complete."
                },
                "complexType": {
                    "original": "any",
                    "resolved": "any",
                    "references": {}
                }
            }];
    }
    static get methods() {
        return {
            "show": {
                "complexType": {
                    "signature": "() => Promise<void>",
                    "parameters": [],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        }
                    },
                    "return": "Promise<void>"
                },
                "docs": {
                    "text": "Shows the tooltip.",
                    "tags": []
                }
            },
            "hide": {
                "complexType": {
                    "signature": "() => Promise<void>",
                    "parameters": [],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        }
                    },
                    "return": "Promise<void>"
                },
                "docs": {
                    "text": "Hides the tooltip.",
                    "tags": []
                }
            }
        };
    }
    static get elementRef() { return "host"; }
    static get watchers() {
        return [{
                "propName": "content",
                "methodName": "setLabel"
            }, {
                "propName": "open",
                "methodName": "handleOpenChange"
            }];
    }
}
