import { __esDecorate, __runInitializers } from "tslib";
import { html, nothing } 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 '../../button/ui-button.js';
import { bound } from '../../../decorators/bound.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 _destructive_decorators;
    let _destructive_initializers = [];
    let _destructive_extraInitializers = [];
    let _confirmValue_decorators;
    let _confirmValue_initializers = [];
    let _confirmValue_extraInitializers = [];
    let _confirmType_decorators;
    let _confirmType_initializers = [];
    let _confirmType_extraInitializers = [];
    let _submitClose_decorators;
    let _submitClose_initializers = [];
    let _submitClose_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 _handleFormSubmit_decorators;
    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 })];
            _destructive_decorators = [property({ type: Boolean })];
            _confirmValue_decorators = [property({ type: String })];
            _confirmType_decorators = [property({ type: String })];
            _submitClose_decorators = [property({ type: Boolean })];
            _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' })];
            _handleFormSubmit_decorators = [bound];
            __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, _destructive_decorators, { kind: "accessor", name: "destructive", static: false, private: false, access: { has: obj => "destructive" in obj, get: obj => obj.destructive, set: (obj, value) => { obj.destructive = value; } }, metadata: _metadata }, _destructive_initializers, _destructive_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, _confirmType_decorators, { kind: "accessor", name: "confirmType", static: false, private: false, access: { has: obj => "confirmType" in obj, get: obj => obj.confirmType, set: (obj, value) => { obj.confirmType = value; } }, metadata: _metadata }, _confirmType_initializers, _confirmType_extraInitializers);
            __esDecorate(this, null, _submitClose_decorators, { kind: "accessor", name: "submitClose", static: false, private: false, access: { has: obj => "submitClose" in obj, get: obj => obj.submitClose, set: (obj, value) => { obj.submitClose = value; } }, metadata: _metadata }, _submitClose_initializers, _submitClose_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, null, _handleFormSubmit_decorators, { kind: "method", name: "handleFormSubmit", static: false, private: false, access: { has: obj => "handleFormSubmit" in obj, get: obj => obj.handleFormSubmit }, metadata: _metadata }, null, _instanceExtraInitializers);
            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; }
        #destructive_accessor_storage = (__runInitializers(this, _confirmLabel_extraInitializers), __runInitializers(this, _destructive_initializers, false
        /**
         * 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
         */
        ));
        /**
         * When true, styles the confirm button with error colors to indicate
         * a destructive action (e.g., delete, remove, etc.).
         * @attribute
         */
        get destructive() { return this.#destructive_accessor_storage; }
        set destructive(value) { this.#destructive_accessor_storage = value; }
        #confirmValue_accessor_storage = (__runInitializers(this, _destructive_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; }
        #confirmType_accessor_storage = (__runInitializers(this, _confirmValue_extraInitializers), __runInitializers(this, _confirmType_initializers, void 0));
        /**
         * The type of the confirm button.
         * This is used to set the button's `type` attribute.
         * If not set, the default is `button`.
         * If set to `submit`, the dialog will trigger the form submission on the parent form.
         * @attribute
         */
        get confirmType() { return this.#confirmType_accessor_storage; }
        set confirmType(value) { this.#confirmType_accessor_storage = value; }
        #submitClose_accessor_storage = (__runInitializers(this, _confirmType_extraInitializers), __runInitializers(this, _submitClose_initializers, void 0));
        /**
         * When the dialog is wrapped in a form, set this to `true` to close the dialog
         * when the form is submitted.
         *
         * Note that the dialog doesn't perform any validation of the form. It only closes
         * when the form is submitted, regardless of the application logic. The `submit` event
         * is dispatched by the dialog when the form is valid.
         * @attribute
         */
        get submitClose() { return this.#submitClose_accessor_storage; }
        set submitClose(value) { this.#submitClose_accessor_storage = value; }
        #dialog_accessor_storage = (__runInitializers(this, _submitClose_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);
        /**
         * A reference to the parent form element.
         * When a form is found, the dialog will hook into the form's submit event
         * and close the dialog when the form is submitted.
         * Since the `submit` event is dispatched when the form is valid,
         * we can use this to close the dialog and not worry about the form validation.
         */
        #form = null;
        constructor() {
            super();
            this.addEventListener('click', this.handleClick);
            this.addEventListener('keydown', this.handleKeyDown);
        }
        connectedCallback() {
            super.connectedCallback();
            this.#form = this.closest('form');
            if (this.#form) {
                this.#form.addEventListener('submit', this.handleFormSubmit);
            }
        }
        disconnectedCallback() {
            super.disconnectedCallback();
            if (this.#form) {
                this.#form.removeEventListener('submit', this.handleFormSubmit);
                this.#form = null;
            }
        }
        handleFormSubmit() {
            if (this.submitClose) {
                this.handleInteraction('confirm');
            }
        }
        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.
                return;
            }
            const { value = '' } = button;
            this.handleInteraction(value);
        }
        handleKeyDown(e) {
            super.handleKeyDown(e);
            if (e.defaultPrevented) {
                return;
            }
            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;
            }
            const detail = {
                cancelled: value === 'dismiss',
            };
            if (this.dialogValue !== undefined) {
                detail.value = this.dialogValue;
            }
            // Dispatch cancelable closing event first
            const closingEvent = new CustomEvent('closing', {
                cancelable: true,
                composed: false,
                bubbles: false,
                detail,
            });
            const canClose = this.dispatchEvent(closingEvent);
            // Only proceed with closing if the event wasn't canceled
            if (!canClose) {
                return;
            }
            this.open = false;
            this.dispatchEvent(new CustomEvent('close', {
                composed: true,
                detail,
            }));
        }
        handleDialogClose() {
            if (!this.open) {
                return;
            }
            const detail = {
                cancelled: true,
            };
            if (this.dialogValue !== undefined) {
                detail.value = this.dialogValue;
            }
            // Dispatch cancelable closing event first
            const closingEvent = new CustomEvent('closing', {
                cancelable: true,
                composed: false,
                bubbles: false,
                detail,
            });
            const canClose = this.dispatchEvent(closingEvent);
            // Only proceed with closing if the event wasn't canceled
            if (!canClose) {
                // If closing was prevented, reopen the dialog
                this.dialog.showModal();
                return;
            }
            this.open = false;
            this.dispatchEvent(new CustomEvent('close', {
                composed: true,
                detail,
            }));
        }
        handleDismiss() {
            this.handleInteraction('dismiss');
        }
        handleConfirm() {
            this.handleInteraction('confirm');
        }
        render() {
            const { modal } = this;
            const dialogClass = modal ? 'modal' : 'non-modal';
            return html `
      <dialog @close="${this.handleDialogClose}" part="dialog" class="${dialogClass}">
        <div class="container">${this.renderContent()}</div>
      </dialog>
    `;
        }
        renderContent() {
            return [this.renderIcon(), this.renderTitle(), this.renderBody(), this.renderButtons()];
        }
        renderIcon() {
            const classes = {
                'icon': true,
                'with-icon': this.hasIcon,
                'destructive': this.destructive,
            };
            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() {
            return html ` <div class="content" part="body"><slot></slot></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}"
        part="negative-action"
        >${dismissLabel}</ui-button
      >
    `;
        }
        #renderConfirmButton() {
            const { confirmLabel, confirmValue = 'confirm', destructive } = this;
            if (!confirmLabel) {
                return nothing;
            }
            const type = this.confirmType ?? 'button';
            const buttonClass = destructive ? 'internal-button destructive' : 'internal-button';
            return html `
      <ui-button
        color="text"
        type="${type}"
        value="${confirmValue}"
        class="${buttonClass}"
        @click="${this.handleConfirm}"
        part="positive-action"
        >${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 slot="button" color="text" value="dismiss">Cancel</ui-button>
 * <ui-button slot="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 closing - A cancelable, non-bubbling event with the `UiDialogClosingReason` as the detail,
 *  dispatched before the dialog closes. If prevented, the dialog will not close.
 * @fires close - A non-bubbling, non-cancellable event with the `UiDialogClosingReason` as the detail.
 */
export default UiDialog;
//# sourceMappingURL=Dialog.js.map