import { __decorate } from "tslib";
import { html, LitElement, nothing } from "lit";
import { property } from "lit/decorators.js";
import { EventUtils } from "@api-client/core/build/browser.js";
import '../../define/ui/ui-button.js';
import '../../define/ui/ui-icon-button.js';
import '../../define/ui/ui-icon.js';
import { classMap } from "lit/directives/class-map.js";
/**
 * Snackbars provide brief messages about app processes at the bottom of the screen.
 *
 * Snackbars inform users of a process that an app has performed or will perform.
 * They appear temporarily, towards the bottom of the screen.
 * They shouldn’t interrupt the user experience, and they don’t require user input to disappear.
 *
 * Only one snackbar may be displayed at a time.
 *
 * A snackbar can contain a single action. "Dismiss" or "cancel" actions are optional.
 *
 * Snackbars communicate messages that are minimally interruptive and don’t require user action.
 *
 * **Caution**, Do not use this element directly.
 *
 * A snackbar is the UI to render in the application. It does not care whether another
 * message is already rendered. Use `SnackNotifications` to manage notification system.
 * The `SnackNotifications` will position toasts directly under the `body` which will make
 * it easier to manage especially when relative / absolute positioning is used.
 *
 * @fires open - When the open state changes. Note, this event is not dispatched when it was programmatically closed.
 * @fires dismiss - When the message was closed via the API.
 * @fires action - When the action button was activated.
 */
export class Snackbar extends LitElement {
    constructor() {
        super();
        /**
         * When set the snackbar does not timeout.
         * It has to be cancelled by user interaction or programmatically.
         *
         * When the `cancellable` is set to false the user won't be able to dismiss the
         * snackbar and the application must remove the snackbar after the process
         * finish. Otherwise another snackbar won't appear.
         *
         * @default false
         * @attribute
         */
        this.persistent = false;
        /**
         * Whether the snackbar can be cancelled via user interaction.
         *
         * @default true
         * @attribute
         */
        this.cancellable = true;
        /**
         * The time in milliseconds after which the message is removed.
         * Has not effect when `persistent` flag is set.
         *
         * @default 5000
         * @attribute
         */
        this.timeout = 5000;
        this.addEventListener('touchstart', this.touchstartHandler.bind(this), { passive: true });
        this.addEventListener('touchend', this.touchendHandler.bind(this), { passive: true });
        this.addEventListener('transitionend', this.transitionendHandler.bind(this), { passive: true });
    }
    updated(cp) {
        if (cp.has('open')) {
            if (this.open) {
                this.setupTimeout();
            }
            else {
                this.clearTimer();
            }
        }
    }
    /**
     * Dismisses the snackbar
     */
    dismiss() {
        this.dismissed = true;
        this.open = false;
    }
    setupTimeout() {
        const { timeout = 5000, persistent } = this;
        this.clearTimer();
        if (persistent) {
            return;
        }
        this.timer = setTimeout(() => {
            this.timeoutHandler();
        }, timeout);
    }
    clearTimer() {
        if (this.timer) {
            clearTimeout(this.timer);
            this.timer = undefined;
        }
    }
    timeoutHandler() {
        this.open = false;
    }
    touchstartHandler(e) {
        if (this.cancellable === false) {
            return;
        }
        this.touchXStart = e.changedTouches[0].screenX;
        this.touchYStart = e.changedTouches[0].screenY;
    }
    touchendHandler(e) {
        if (this.cancellable === false) {
            return;
        }
        const { touchXStart, touchYStart } = this;
        if (typeof touchXStart !== 'number' || typeof touchYStart !== 'number') {
            return;
        }
        this.touchXStart = undefined;
        this.touchYStart = undefined;
        const endX = e.changedTouches[0].screenX;
        const endY = e.changedTouches[0].screenY;
        const xDelta = Math.abs(endX - touchXStart);
        const yDelta = Math.abs(endY - touchYStart);
        const threshold = 20;
        if (xDelta > threshold || yDelta > threshold) {
            this.open = false;
        }
    }
    actionHandler() {
        this.dispatchEvent(new Event('action'));
        this.dismiss();
    }
    transitionendHandler() {
        if (!this.dismissed) {
            this.dispatchEvent(new Event('open'));
        }
        else {
            this.dismissed = false;
            this.dispatchEvent(new Event('dismiss'));
        }
    }
    closeHandler() {
        this.open = false;
    }
    render() {
        const classes = {
            body: true,
            withAction: !!this.action,
            withClose: !!this.close,
        };
        return html `
    <div class="${classMap(classes)}">
      <slot></slot>
    </div>
    ${this.renderAction()}
    ${this.renderIcon()}
    `;
    }
    renderAction() {
        const { action } = this;
        if (!action) {
            return nothing;
        }
        return html `
    <ui-button type="text" class="action" @click="${this.actionHandler}" @action="${EventUtils.cancelEvent}">${action}</ui-button>
    `;
    }
    renderIcon() {
        const { close } = this;
        if (!close) {
            return nothing;
        }
        return html `
    <ui-icon-button @click="${this.closeHandler}" class="icon" @action="${EventUtils.cancelEvent}">
      <ui-icon icon="close"></ui-icon>
    </ui-icon-button>
    `;
    }
}
__decorate([
    property({ type: Boolean })
], Snackbar.prototype, "persistent", void 0);
__decorate([
    property({ type: Boolean })
], Snackbar.prototype, "cancellable", void 0);
__decorate([
    property({ type: Number })
], Snackbar.prototype, "timeout", void 0);
__decorate([
    property({ type: String })
], Snackbar.prototype, "action", void 0);
__decorate([
    property({ type: Boolean })
], Snackbar.prototype, "close", void 0);
__decorate([
    property({ type: Boolean, reflect: true })
], Snackbar.prototype, "open", void 0);
//# sourceMappingURL=Snackbar.js.map