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;
};
import { assertExists } from '@blockeditor/global/utils';
import { arrow, flip, offset, } from '@floating-ui/dom';
import { css, html, LitElement, unsafeCSS } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import { styleMap } from 'lit/directives/style-map.js';
import { HoverController } from '../hover/index.js';
const styles = css `
  .affine-tooltip {
    box-sizing: border-box;
    max-width: 280px;
    min-height: 32px;
    font-family: var(--affine-font-family);
    font-size: var(--affine-font-sm);
    border-radius: 4px;
    padding: 6px 12px;
    color: var(--affine-white);
    background: var(--affine-tooltip);

    display: flex;
    justify-content: center;
    align-items: center;
  }

  .arrow {
    position: absolute;

    width: 0;
    height: 0;
  }
`;
// See http://apps.eky.hk/css-triangle-generator/
const TRIANGLE_HEIGHT = 6;
const triangleMap = {
    top: {
        bottom: '-6px',
        borderStyle: 'solid',
        borderWidth: '6px 5px 0 5px',
        borderColor: 'var(--affine-tooltip) transparent transparent transparent',
    },
    right: {
        left: '-6px',
        borderStyle: 'solid',
        borderWidth: '5px 6px 5px 0',
        borderColor: 'transparent var(--affine-tooltip) transparent transparent',
    },
    bottom: {
        top: '-6px',
        borderStyle: 'solid',
        borderWidth: '0 5px 6px 5px',
        borderColor: 'transparent transparent var(--affine-tooltip) transparent',
    },
    left: {
        right: '-6px',
        borderStyle: 'solid',
        borderWidth: '5px 0 5px 6px',
        borderColor: 'transparent transparent transparent var(--affine-tooltip)',
    },
};
// Ported from https://floating-ui.com/docs/tutorial#arrow-middleware
const updateArrowStyles = ({ placement, middlewareData, }) => {
    const arrowX = middlewareData.arrow?.x;
    const arrowY = middlewareData.arrow?.y;
    const triangleStyles = triangleMap[placement.split('-')[0]];
    return {
        left: arrowX != null ? `${arrowX}px` : '',
        top: arrowY != null ? `${arrowY}px` : '',
        ...triangleStyles,
    };
};
/**
 * @example
 * ```ts
 * // Simple usage
 * html`
 * <affine-tooltip>Content</affine-tooltip>
 * `
 * // With placement
 * html`
 * <affine-tooltip tip-position="top">
 *   Content
 * </affine-tooltip>
 * `
 *
 * // With custom properties
 * html`
 * <affine-tooltip
 *   .zIndex=${0}
 *   .offset=${4}
 *   .autoFlip=${true}
 *   .arrow=${true}
 *   .tooltipStyle=${css`:host { z-index: 0; --affine-tooltip: #fff; }`}
 *   .allowInteractive=${false}
 * >
 *   Content
 * </affine-tooltip>
 * `
 * ```
 */
let Tooltip = class Tooltip extends LitElement {
    constructor() {
        super(...arguments);
        this.placement = 'top';
        this.zIndex = 'var(--affine-z-index-popover)';
        this.tooltipStyle = css ``;
        /**
         * changes the placement of the floating element in order to keep it in view,
         * with the ability to flip to any placement.
         *
         * See https://floating-ui.com/docs/flip
         */
        this.autoFlip = true;
        /**
         * Show a triangle arrow pointing to the reference element.
         */
        this.arrow = true;
        /**
         * Default is `4px`
         *
         * See https://floating-ui.com/docs/offset
         */
        this.offset = 4;
        /**
         * Allow the tooltip to be interactive.
         * eg. allow the user to select text in the tooltip.
         */
        this.allowInteractive = false;
        this._hoverController = new HoverController(this, () => {
            // const parentElement = this.parentElement;
            // if (
            //   parentElement &&
            //   'disabled' in parentElement &&
            //   parentElement.disabled
            // )
            //   return null;
            if (this.hidden)
                return null;
            let arrowStyles = {};
            return {
                template: ({ positionSlot, updatePortal }) => {
                    positionSlot.on(data => {
                        // The tooltip placement may change,
                        // so we need to update the arrow position
                        if (this.arrow) {
                            arrowStyles = updateArrowStyles(data);
                        }
                        else {
                            arrowStyles = {};
                        }
                        updatePortal();
                    });
                    const slot = this.shadowRoot?.querySelector('slot');
                    if (!slot)
                        throw new Error('slot not found in tooltip!');
                    // slot.addEventListener('slotchange', () => updatePortal, {
                    //   once: true,
                    // });
                    const slottedChildren = slot
                        .assignedNodes()
                        .map(node => node.cloneNode(true));
                    return html `
            <style>
              ${this._getStyles()}
            </style>
            <div class="affine-tooltip" role="tooltip">${slottedChildren}</div>
            <div class="arrow" style=${styleMap(arrowStyles)}></div>
          `;
                },
                computePosition: portalRoot => ({
                    referenceElement: this.parentElement,
                    placement: this.placement,
                    middleware: [
                        this.autoFlip && flip({ padding: 12 }),
                        offset((this.arrow ? TRIANGLE_HEIGHT : 0) + this.offset),
                        arrow({
                            element: portalRoot.shadowRoot.querySelector('.arrow'),
                        }),
                    ],
                    autoUpdate: true,
                }),
            };
        }, {
            leaveDelay: 0,
            // The tooltip is not interactive by default
            safeBridge: false,
        });
    }
    connectedCallback() {
        super.connectedCallback();
        const parent = this.parentElement;
        assertExists(parent, 'Tooltip must have a parent element');
        // Wait for render
        setTimeout(() => {
            this._hoverController.setReference(parent);
        }, 0);
    }
    getPortal() {
        return this._hoverController.portal;
    }
    _getStyles() {
        return css `
      ${styles}
      :host {
        z-index: ${unsafeCSS(this.zIndex)};
        ${
        // All the styles are applied to the portal element
        unsafeCSS(this.style.cssText)}
      }

      ${this.allowInteractive
            ? css ``
            : css `
            :host {
              pointer-events: none;
            }
          `}

      ${this.tooltipStyle}
    `;
    }
    render() {
        // The actual tooltip will render as a portal, and all content inside the slot will be treated as a template.
        // See https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_templates_and_slots
        return html `<slot></slot>`;
    }
};
Tooltip.styles = css `
    :host {
      display: none;
    }
  `;
__decorate([
    property({ attribute: 'tip-position' })
], Tooltip.prototype, "placement", void 0);
__decorate([
    property({ attribute: false })
], Tooltip.prototype, "zIndex", void 0);
__decorate([
    property({ attribute: false })
], Tooltip.prototype, "tooltipStyle", void 0);
__decorate([
    property({ attribute: false })
], Tooltip.prototype, "autoFlip", void 0);
__decorate([
    property({ attribute: false })
], Tooltip.prototype, "arrow", void 0);
__decorate([
    property({ attribute: false })
], Tooltip.prototype, "offset", void 0);
__decorate([
    property({ attribute: false })
], Tooltip.prototype, "allowInteractive", void 0);
Tooltip = __decorate([
    customElement('affine-tooltip')
], Tooltip);
export { Tooltip };
//# sourceMappingURL=tooltip.js.map