import { __esDecorate, __runInitializers, __setFunctionName } from "tslib";
import { html, nothing, adoptStyles } from 'lit';
import { property, query, queryAssignedElements, queryAssignedNodes, state } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { UiElement } from '../../UiElement.js';
import { isDisabled, setDisabled } from '../../../lib/disabled.js';
import { ifDefined } from 'lit/directives/if-defined.js';
import { SyntheticSubmitEvent } from '../../../events/SyntheticSubmitEvent.js';
import '../../button/ui-button.js';
let UiDialog = (() => {
    let _classSuper = UiElement;
    let _instanceExtraInitializers = [];
    let _set_disabled_decorators;
    let _modal_decorators;
    let _modal_initializers = [];
    let _modal_extraInitializers = [];
    let _open_decorators;
    let _open_initializers = [];
    let _open_extraInitializers = [];
    let _dismissLabel_decorators;
    let _dismissLabel_initializers = [];
    let _dismissLabel_extraInitializers = [];
    let _confirmLabel_decorators;
    let _confirmLabel_initializers = [];
    let _confirmLabel_extraInitializers = [];
    let _useForm_decorators;
    let _useForm_initializers = [];
    let _useForm_extraInitializers = [];
    let _confirmValue_decorators;
    let _confirmValue_initializers = [];
    let _confirmValue_extraInitializers = [];
    let _dialog_decorators;
    let _dialog_initializers = [];
    let _dialog_extraInitializers = [];
    let _hasIcon_decorators;
    let _hasIcon_initializers = [];
    let _hasIcon_extraInitializers = [];
    let _hasTitle_decorators;
    let _hasTitle_initializers = [];
    let _hasTitle_extraInitializers = [];
    let _hasButton_decorators;
    let _hasButton_initializers = [];
    let _hasButton_extraInitializers = [];
    let _icons_decorators;
    let _icons_initializers = [];
    let _icons_extraInitializers = [];
    let _titles_decorators;
    let _titles_initializers = [];
    let _titles_extraInitializers = [];
    let _buttons_decorators;
    let _buttons_initializers = [];
    let _buttons_extraInitializers = [];
    let _private_inject_decorators;
    let _private_inject_initializers = [];
    let _private_inject_extraInitializers = [];
    let _private_inject_descriptor;
    return class UiDialog extends _classSuper {
        static {
            const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
            _set_disabled_decorators = [property({ reflect: true, type: Boolean })];
            _modal_decorators = [property({ type: Boolean })];
            _open_decorators = [property({ type: Boolean })];
            _dismissLabel_decorators = [property({ type: String })];
            _confirmLabel_decorators = [property({ type: String })];
            _useForm_decorators = [property({ type: Boolean })];
            _confirmValue_decorators = [property({ type: String })];
            _dialog_decorators = [query('dialog')];
            _hasIcon_decorators = [state()];
            _hasTitle_decorators = [state()];
            _hasButton_decorators = [state()];
            _icons_decorators = [queryAssignedElements({ flatten: true, slot: 'icon' })];
            _titles_decorators = [queryAssignedNodes({ flatten: true, slot: 'title' })];
            _buttons_decorators = [queryAssignedElements({ flatten: true, slot: 'button' })];
            _private_inject_decorators = [state()];
            __esDecorate(this, null, _set_disabled_decorators, { kind: "setter", name: "disabled", static: false, private: false, access: { has: obj => "disabled" in obj, set: (obj, value) => { obj.disabled = value; } }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(this, null, _modal_decorators, { kind: "accessor", name: "modal", static: false, private: false, access: { has: obj => "modal" in obj, get: obj => obj.modal, set: (obj, value) => { obj.modal = value; } }, metadata: _metadata }, _modal_initializers, _modal_extraInitializers);
            __esDecorate(this, null, _open_decorators, { kind: "accessor", name: "open", static: false, private: false, access: { has: obj => "open" in obj, get: obj => obj.open, set: (obj, value) => { obj.open = value; } }, metadata: _metadata }, _open_initializers, _open_extraInitializers);
            __esDecorate(this, null, _dismissLabel_decorators, { kind: "accessor", name: "dismissLabel", static: false, private: false, access: { has: obj => "dismissLabel" in obj, get: obj => obj.dismissLabel, set: (obj, value) => { obj.dismissLabel = value; } }, metadata: _metadata }, _dismissLabel_initializers, _dismissLabel_extraInitializers);
            __esDecorate(this, null, _confirmLabel_decorators, { kind: "accessor", name: "confirmLabel", static: false, private: false, access: { has: obj => "confirmLabel" in obj, get: obj => obj.confirmLabel, set: (obj, value) => { obj.confirmLabel = value; } }, metadata: _metadata }, _confirmLabel_initializers, _confirmLabel_extraInitializers);
            __esDecorate(this, null, _useForm_decorators, { kind: "accessor", name: "useForm", static: false, private: false, access: { has: obj => "useForm" in obj, get: obj => obj.useForm, set: (obj, value) => { obj.useForm = value; } }, metadata: _metadata }, _useForm_initializers, _useForm_extraInitializers);
            __esDecorate(this, null, _confirmValue_decorators, { kind: "accessor", name: "confirmValue", static: false, private: false, access: { has: obj => "confirmValue" in obj, get: obj => obj.confirmValue, set: (obj, value) => { obj.confirmValue = value; } }, metadata: _metadata }, _confirmValue_initializers, _confirmValue_extraInitializers);
            __esDecorate(this, null, _dialog_decorators, { kind: "accessor", name: "dialog", static: false, private: false, access: { has: obj => "dialog" in obj, get: obj => obj.dialog, set: (obj, value) => { obj.dialog = value; } }, metadata: _metadata }, _dialog_initializers, _dialog_extraInitializers);
            __esDecorate(this, null, _hasIcon_decorators, { kind: "accessor", name: "hasIcon", static: false, private: false, access: { has: obj => "hasIcon" in obj, get: obj => obj.hasIcon, set: (obj, value) => { obj.hasIcon = value; } }, metadata: _metadata }, _hasIcon_initializers, _hasIcon_extraInitializers);
            __esDecorate(this, null, _hasTitle_decorators, { kind: "accessor", name: "hasTitle", static: false, private: false, access: { has: obj => "hasTitle" in obj, get: obj => obj.hasTitle, set: (obj, value) => { obj.hasTitle = value; } }, metadata: _metadata }, _hasTitle_initializers, _hasTitle_extraInitializers);
            __esDecorate(this, null, _hasButton_decorators, { kind: "accessor", name: "hasButton", static: false, private: false, access: { has: obj => "hasButton" in obj, get: obj => obj.hasButton, set: (obj, value) => { obj.hasButton = value; } }, metadata: _metadata }, _hasButton_initializers, _hasButton_extraInitializers);
            __esDecorate(this, null, _icons_decorators, { kind: "accessor", name: "icons", static: false, private: false, access: { has: obj => "icons" in obj, get: obj => obj.icons, set: (obj, value) => { obj.icons = value; } }, metadata: _metadata }, _icons_initializers, _icons_extraInitializers);
            __esDecorate(this, null, _titles_decorators, { kind: "accessor", name: "titles", static: false, private: false, access: { has: obj => "titles" in obj, get: obj => obj.titles, set: (obj, value) => { obj.titles = value; } }, metadata: _metadata }, _titles_initializers, _titles_extraInitializers);
            __esDecorate(this, null, _buttons_decorators, { kind: "accessor", name: "buttons", static: false, private: false, access: { has: obj => "buttons" in obj, get: obj => obj.buttons, set: (obj, value) => { obj.buttons = value; } }, metadata: _metadata }, _buttons_initializers, _buttons_extraInitializers);
            __esDecorate(this, _private_inject_descriptor = { get: __setFunctionName(function () { return this.#inject_accessor_storage; }, "#inject", "get"), set: __setFunctionName(function (value) { this.#inject_accessor_storage = value; }, "#inject", "set") }, _private_inject_decorators, { kind: "accessor", name: "#inject", static: false, private: true, access: { has: obj => #inject in obj, get: obj => obj.#inject, set: (obj, value) => { obj.#inject = value; } }, metadata: _metadata }, _private_inject_initializers, _private_inject_extraInitializers);
            if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
        }
        get disabled() {
            return isDisabled(this);
        }
        /**
         * When set, the button is a disabled state.
         * @attribute
         */
        set disabled(value) {
            const old = isDisabled(this);
            setDisabled(this, value);
            this.requestUpdate('disabled', old);
        }
        #modal_accessor_storage = (__runInitializers(this, _instanceExtraInitializers), __runInitializers(this, _modal_initializers, false
        /**
         * Toggles visibility of the dialog.
         * Note, the dialog is opened asynchronously after the update is performed.
         * @attribute
         */
        ));
        /**
         * Opens the dialog as modal when toggling dialog's open state.
         *
         * Setting this value after the dialog was opened has no effect.
         *
         * @attribute
         */
        get modal() { return this.#modal_accessor_storage; }
        set modal(value) { this.#modal_accessor_storage = value; }
        #open_accessor_storage = (__runInitializers(this, _modal_extraInitializers), __runInitializers(this, _open_initializers, false
        /**
         * Imperative access to create a dismiss button.
         * When set this will render a dismiss button at the end of the buttons line, before the `confirmLabel` button.
         * @attribute
         */
        ));
        /**
         * Toggles visibility of the dialog.
         * Note, the dialog is opened asynchronously after the update is performed.
         * @attribute
         */
        get open() { return this.#open_accessor_storage; }
        set open(value) { this.#open_accessor_storage = value; }
        #dismissLabel_accessor_storage = (__runInitializers(this, _open_extraInitializers), __runInitializers(this, _dismissLabel_initializers, void 0));
        /**
         * Imperative access to create a dismiss button.
         * When set this will render a dismiss button at the end of the buttons line, before the `confirmLabel` button.
         * @attribute
         */
        get dismissLabel() { return this.#dismissLabel_accessor_storage; }
        set dismissLabel(value) { this.#dismissLabel_accessor_storage = value; }
        #confirmLabel_accessor_storage = (__runInitializers(this, _dismissLabel_extraInitializers), __runInitializers(this, _confirmLabel_initializers, void 0));
        /**
         * Imperative access to create a confirm button.
         * When set this will render a confirm button at the end of the buttons line, after the `dismissLabel` button.
         * @attribute
         */
        get confirmLabel() { return this.#confirmLabel_accessor_storage; }
        set confirmLabel(value) { this.#confirmLabel_accessor_storage = value; }
        #useForm_accessor_storage = (__runInitializers(this, _confirmLabel_extraInitializers), __runInitializers(this, _useForm_initializers, void 0));
        /**
         * Part of the imperative access to the element.
         * When set, it wraps the content in a `<form>` element.
         * When this is enabled the following will happen:
         * - The `confirm` button will get `type="submit"`
         * - The form `method` attribute is set to `dialog`
         * - The form `id` attribute is set to a random string. You can get it from the `formId` getter.
         * - The dialog will dispatch the same `submit` event as the form.
         * - When the `submit` event dispatched by the dialog gets cancelled, then:
         *  - The original submit event also gets cancelled.
         *  - The default confirm action is not invoked
         *  - The dialog stays opened
         * - When the submit event is not cancelled, then:
         *  - The default confirm action is invoked.
         *  - The dialog is closed.
         */
        get useForm() { return this.#useForm_accessor_storage; }
        set useForm(value) { this.#useForm_accessor_storage = value; }
        #confirmValue_accessor_storage = (__runInitializers(this, _useForm_extraInitializers), __runInitializers(this, _confirmValue_initializers, void 0));
        /**
         * Only when `confirmLabel` is set.
         * Defines the value associated with the button's name when it's submitted with the form data.
         * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#value}
         * @attribute
         */
        get confirmValue() { return this.#confirmValue_accessor_storage; }
        set confirmValue(value) { this.#confirmValue_accessor_storage = value; }
        #dialog_accessor_storage = (__runInitializers(this, _confirmValue_extraInitializers), __runInitializers(this, _dialog_initializers, void 0));
        /**
         * A reference to the underlying dialog element.
         */
        get dialog() { return this.#dialog_accessor_storage; }
        set dialog(value) { this.#dialog_accessor_storage = value; }
        #hasIcon_accessor_storage = (__runInitializers(this, _dialog_extraInitializers), __runInitializers(this, _hasIcon_initializers, false));
        get hasIcon() { return this.#hasIcon_accessor_storage; }
        set hasIcon(value) { this.#hasIcon_accessor_storage = value; }
        #hasTitle_accessor_storage = (__runInitializers(this, _hasIcon_extraInitializers), __runInitializers(this, _hasTitle_initializers, false));
        get hasTitle() { return this.#hasTitle_accessor_storage; }
        set hasTitle(value) { this.#hasTitle_accessor_storage = value; }
        #hasButton_accessor_storage = (__runInitializers(this, _hasTitle_extraInitializers), __runInitializers(this, _hasButton_initializers, false));
        get hasButton() { return this.#hasButton_accessor_storage; }
        set hasButton(value) { this.#hasButton_accessor_storage = value; }
        #icons_accessor_storage = (__runInitializers(this, _hasButton_extraInitializers), __runInitializers(this, _icons_initializers, void 0));
        get icons() { return this.#icons_accessor_storage; }
        set icons(value) { this.#icons_accessor_storage = value; }
        #titles_accessor_storage = (__runInitializers(this, _icons_extraInitializers), __runInitializers(this, _titles_initializers, void 0));
        get titles() { return this.#titles_accessor_storage; }
        set titles(value) { this.#titles_accessor_storage = value; }
        #buttons_accessor_storage = (__runInitializers(this, _titles_extraInitializers), __runInitializers(this, _buttons_initializers, void 0));
        get buttons() { return this.#buttons_accessor_storage; }
        set buttons(value) { this.#buttons_accessor_storage = value; }
        /**
         * To be set by a child class when closing the dialog.
         * This is passed to the close event.
         */
        dialogValue = __runInitializers(this, _buttons_extraInitializers);
        #formId;
        get formId() {
            return this.#formId;
        }
        #inject_accessor_storage = __runInitializers(this, _private_inject_initializers, void 0);
        get #inject() { return _private_inject_descriptor.get.call(this); }
        set #inject(value) { return _private_inject_descriptor.set.call(this, value); }
        #pendingStyles = __runInitializers(this, _private_inject_extraInitializers);
        constructor() {
            super();
            this.addEventListener('click', this.handleClick);
            this.addEventListener('keydown', this.handleKeyDown);
        }
        /**
         * Allows to inject a template into the internals of the element.
         * This is helpful when working with imperative dialogs.
         * @param content The content to inject into the body.
         */
        inject(content, styles) {
            this.#inject = content;
            if (styles) {
                if (this.shadowRoot) {
                    adoptStyles(this.shadowRoot, styles);
                }
                else {
                    if (!this.#pendingStyles) {
                        this.#pendingStyles = [];
                    }
                    this.#pendingStyles.push(...styles);
                }
            }
            if (this.shadowRoot && styles) {
                adoptStyles(this.shadowRoot, styles);
            }
        }
        firstUpdated() {
            const styles = this.#pendingStyles;
            if (styles) {
                const root = this.shadowRoot;
                const all = [...root.adoptedStyleSheets, ...styles];
                adoptStyles(this.shadowRoot, all);
            }
        }
        willUpdate(cp) {
            if (cp.has('useForm') && this.useForm && !this.#formId) {
                const r = (Math.random() + 1).toString(36).substring(7);
                this.#formId = `form-${r}`;
            }
        }
        handleClick(e) {
            super.handleClick(e);
            const path = e.composedPath();
            const { buttons } = this;
            const button = path.find((i) => buttons.includes(i));
            if (!button) {
                return;
            }
            if (button.type === 'submit') {
                // Adds support for forms.
                // When a form's submit button is clicked we yield the flow control to the form.
                // This way the form can handle the submit event.
                e.preventDefault();
                return;
            }
            const { value = '' } = button;
            this.handleInteraction(value);
        }
        handleKeyDown(e) {
            super.handleKeyDown(e);
            if (e.key === 'Escape') {
                this.handleInteraction('dismiss');
            }
        }
        updated(changedProperties) {
            if (changedProperties.has('open')) {
                this.#controlVisibility();
            }
            super.updated(changedProperties);
        }
        #controlVisibility() {
            const { dialog, modal, open } = this;
            if (!dialog) {
                return;
            }
            if (open) {
                if (modal) {
                    dialog.showModal();
                }
                else {
                    dialog.show();
                }
            }
            else {
                dialog.close();
            }
        }
        #handleSlotChange() {
            const { icons, titles, buttons } = this;
            this.hasIcon = !!icons && !!icons.length;
            this.hasTitle = !!titles && !!titles.length;
            this.hasButton = !!buttons && !!buttons.length;
        }
        handleInteraction(value) {
            if (!['dismiss', 'confirm'].includes(value)) {
                return;
            }
            this.open = false;
            const detail = {
                cancelled: value === 'dismiss',
            };
            if (this.dialogValue !== undefined) {
                detail.value = this.dialogValue;
            }
            this.dispatchEvent(new CustomEvent('close', {
                composed: true,
                detail,
            }));
        }
        handleDialogClose() {
            if (!this.open) {
                return;
            }
            this.open = false;
            this.handleInteraction('dismiss');
        }
        handleDismiss() {
            this.handleInteraction('dismiss');
        }
        handleConfirm() {
            if (!this.useForm) {
                this.handleInteraction('confirm');
            }
        }
        #handleSubmit(event) {
            const form = event.target;
            const copy = new SyntheticSubmitEvent(event.type, form, {
                submitter: event.submitter,
                cancelable: true,
                bubbles: false,
                composed: false,
            });
            const dispatched = this.dispatchEvent(copy);
            if (dispatched) {
                this.handleInteraction('confirm');
            }
            else {
                event.preventDefault();
            }
        }
        render() {
            const { useForm } = this;
            return html `
      <dialog @close="${this.handleDialogClose}">
        <div class="container">${useForm ? this.#renderFormContent() : this.renderContent()}</div>
      </dialog>
    `;
        }
        renderContent() {
            return [this.renderIcon(), this.renderTitle(), this.renderBody(), this.renderButtons()];
        }
        #renderFormContent() {
            return html `
      <form id="${ifDefined(this.formId)}" method="dialog" @submit="${this.#handleSubmit}">
        ${this.renderContent()}
      </form>
    `;
        }
        renderIcon() {
            const classes = {
                'icon': true,
                'with-icon': this.hasIcon,
            };
            return html `
      <div class="${classMap(classes)}" part="icon">
        <slot name="icon" @slotchange="${this.#handleSlotChange}"></slot>
      </div>
    `;
        }
        renderTitle() {
            const classes = {
                'title': true,
                'with-title': this.hasTitle,
            };
            return html `
      <div class="${classMap(classes)}" part="title">
        <slot name="title" @slotchange="${this.#handleSlotChange}"></slot>
      </div>
    `;
        }
        renderBody() {
            let content = this.#inject;
            if (typeof content === 'function') {
                content = content();
            }
            const injected = content || nothing;
            return html ` <div class="content"><slot></slot>${injected}</div> `;
        }
        renderButtons() {
            const classes = {
                'buttons': true,
                'with-buttons': this.hasButton || !!this.confirmLabel || !!this.dismissLabel,
            };
            return html `
      <div class="${classMap(classes)}" part="button">
        <slot name="button" @slotchange="${this.#handleSlotChange}"></slot>
        ${this.#renderDismissButton()} ${this.#renderConfirmButton()}
      </div>
    `;
        }
        #renderDismissButton() {
            const { dismissLabel } = this;
            if (!dismissLabel) {
                return nothing;
            }
            return html `
      <ui-button color="text" value="dismiss" class="internal-button" @click="${this.handleDismiss}"
        >${dismissLabel}</ui-button
      >
    `;
        }
        #renderConfirmButton() {
            const { confirmLabel, confirmValue = 'confirm', useForm } = this;
            if (!confirmLabel) {
                return nothing;
            }
            const type = useForm ? 'submit' : 'button';
            return html `
      <ui-button
        color="text"
        type="${type}"
        value="${confirmValue}"
        class="internal-button"
        @click="${this.handleConfirm}"
        >${confirmLabel}</ui-button
      >
    `;
        }
    };
})();
/**
 * Styled dialog using a native `<dialog>` element under the hood.
 * Note, since native dialog renders in the top layer it is not necessary
 * to place the dialog in the `<body>`.
 *
 * **Using Buttons**
 *
 * The dialog automatically recognizes buttons with values `confirm` and `dismiss`
 * to close the dialog and dispatch the `close` event. The event has additional
 * closing reason detail.
 *
 * ```javascript
 * <ui-button color="text" value="dismiss">Cancel</ui-button>
 * <ui-button color="text" value="confirm">Take action</ui-button>
 * ```
 *
 * ```javascript
 * <button value="dismiss">Cancel</button>
 * <button value="confirm">Take action</button>
 * ```
 *
 * The detail object of the `close` event has the following properties:
 * - cancelled - Whether the dialog was cancelled by either activating the `dismiss` button or by pressing escape.
 *
 * The `close` event is only dispatched when the user interact with the dialog. Imperative control of the
 * dialog won't trigger the close button.
 *
 * ** Full example**
 *
 * ```javascript
 * <ui-dialog modal>
 *  <ui-icon slot="icon" icon="delete"></ui-icon>
 *
 *  <span slot="title">Delete photos?</span>
 *  <p>This action will permanently remove the selected pictures from your account.</p>
 *
 *  <ui-button color="text" slot="button" value="dismiss" type="text">Cancel</ui-button>
 *  <ui-button color="text" slot="button" value="confirm" type="text">Confirm</ui-button>
 * </ui-dialog>
 * ```
 *
 * @slot - The slot for the content of the dialog.
 * @slot icon - The slot to place the dialog icon
 * @slot title - The slot to place the dialog title. Do not put elements here, just the text.
 * @slot button - The slot to place the dialog buttons. Use the `confirm` or `dismiss`
 *  buttons to automatically close the dialog.
 * @fires close - A non-bubbling, non-cancellable event with the `UiDialogClosingReason` as the detail.
 */
export default UiDialog;
//# sourceMappingURL=Dialog.js.map