import { __decorate } from "tslib";
import '../nile-icon';
import { classMap } from 'lit/directives/class-map.js';
import { customElement, property, query, state } from 'lit/decorators.js';
import { FormControlController, validValidityState } from '../internal/form';
import { HasSlotController } from '../internal/slot';
import { html } from 'lit';
import { ifDefined } from 'lit/directives/if-defined.js';
import { watch } from '../internal/watch';
import { styles } from './nile-button.css';
import NileElement from '../internal/nile-element';
import { literal } from 'lit/static-html.js';
/**
 * @summary Buttons represent actions that are available to the user.
 * @status stable
 * @since 2.0
 *
 * @dependency nile-icon
 * @dependency nile-spinner
 *
 * @event nile-blur - Emitted when the button loses focus.
 * @event nile-focus - Emitted when the button gains focus.
 * @event nile-invalid - Emitted when the form control has been checked for validity and its constraints aren't satisfied.
 *
 * @slot - The button's label.
 * @slot prefix - A presentational prefix icon or similar element.
 * @slot suffix - A presentational suffix icon or similar element.
 *
 * @csspart base - The component's base wrapper.
 * @csspart prefix - The container that wraps the prefix.
 * @csspart label - The button's label.
 * @csspart suffix - The container that wraps the suffix.
 * @csspart caret - The button's caret icon, an `<nile-icon>` element.
 */
let NileButton = class NileButton extends NileElement {
    constructor() {
        super(...arguments);
        this.formControlController = new FormControlController(this, {
            form: input => {
                // Buttons support a form attribute that points to an arbitrary form, so if this attribute is set we need to query
                // the form from the same root using its id
                if (input.hasAttribute('form')) {
                    const doc = input.getRootNode();
                    const formId = input.getAttribute('form');
                    return doc.getElementById(formId);
                }
                // Fall back to the closest containing form
                return input.closest('form');
            },
            assumeInteractionOn: ['click'],
        });
        this.hasSlotController = new HasSlotController(this, '[default]', 'prefix', 'suffix');
        this.hasFocus = false;
        this.invalid = false;
        this.title = ''; // make reactive to pass through
        /** The button's theme variant. */
        this.variant = 'primary';
        /** The button's size. */
        this.size = 'medium';
        /** Draws the button with a caret. Used to indicate that the button triggers a dropdown menu or similar behavior. */
        this.caret = false;
        /** Disables the button. */
        this.disabled = false;
        /** Draws the button in a loading state. */
        this.loading = false;
        /** Draws an outlined button. */
        this.outline = false;
        /** Draws a pill-style button with rounded edges. */
        this.pill = false;
        /**
         * Draws a circular icon button. When this attribute is present, the button expects a single `<nile-icon>` in the
         * default slot.
         */
        this.circle = false;
        /**
         * The type of button. Note that the default value is `button` instead of `submit`, which is opposite of how native
         * `<button>` elements behave. When the type is `submit`, the button will submit the surrounding form.
         */
        this.type = 'button';
        /**
         * The name of the button, submitted as a name/value pair with form data, but only when this button is the submitter.
         * This attribute is ignored when `href` is present.
         */
        this.name = '';
        /**
         * The value of the button, submitted as a pair with the button's name as part of the form data, but only when this
         * button is the submitter. This attribute is ignored when `href` is present.
         */
        this.value = '';
        /** When set, the underlying button will be rendered as an `<a>` with this `href` instead of a `<button>`. */
        this.href = '';
        /**
         * When using `href`, this attribute will map to the underlying link's `rel` attribute. Unlike regular links, the
         * default is `noreferrer noopener` to prevent security exploits. However, if you're using `target` to point to a
         * specific tab/window, this will prevent that from working correctly. You can remove or change the default value by
         * setting the attribute to an empty string or a value of your choice, respectively.
         */
        this.rel = 'noreferrer noopener';
        this.hideBorder = false;
    }
    /** Gets the validity state object */
    get validity() {
        if (this.isButton()) {
            return this.button.validity;
        }
        return validValidityState;
    }
    /** Gets the validation message */
    get validationMessage() {
        if (this.isButton()) {
            return this.button.validationMessage;
        }
        return '';
    }
    connectedCallback() {
        super.connectedCallback();
        this.handleHostClick = this.handleHostClick.bind(this);
        this.addEventListener('click', this.handleHostClick);
        this.emit('nile-init');
    }
    disconnectedCallback() {
        super.disconnectedCallback();
        this.removeEventListener('click', this.handleHostClick);
        this.emit('nile-destroy');
    }
    firstUpdated() {
        if (this.isButton()) {
            this.formControlController.updateValidity();
        }
    }
    handleBlur() {
        this.hasFocus = false;
        this.emit('nile-blur');
    }
    handleFocus() {
        this.hasFocus = true;
        this.emit('nile-focus');
    }
    handleClick() {
        if (this.type === 'submit') {
            this.formControlController.submit(this);
        }
        if (this.type === 'reset') {
            this.formControlController.reset(this);
        }
    }
    handleHostClick(event) {
        // Prevent the click event from being emitted when the button is disabled or loading
        if (this.disabled || this.loading) {
            event.preventDefault();
            event.stopImmediatePropagation();
        }
    }
    handleInvalid(event) {
        this.formControlController.setValidity(false);
        this.formControlController.emitInvalidEvent(event);
    }
    isButton() {
        return this.href ? false : true;
    }
    isLink() {
        return this.href ? true : false;
    }
    handleDisabledChange() {
        if (this.isButton()) {
            // Disabled form controls are always valid
            this.formControlController.setValidity(this.disabled);
        }
    }
    /** Simulates a click on the button. */
    click() {
        this.button.click();
    }
    /** Sets focus on the button. */
    focus(options) {
        this.button.focus(options);
    }
    /** Removes focus from the button. */
    blur() {
        this.button.blur();
    }
    /** Checks for validity but does not show a validation message. Returns `true` when valid and `false` when invalid. */
    checkValidity() {
        if (this.isButton()) {
            return this.button.checkValidity();
        }
        return true;
    }
    /** Gets the associated form, if one exists. */
    getForm() {
        return this.formControlController.getForm();
    }
    /** Checks for validity and shows the browser's validation message if the control is invalid. */
    reportValidity() {
        if (this.isButton()) {
            return this.button.reportValidity();
        }
        return true;
    }
    /** Sets a custom validation message. Pass an empty string to restore validity. */
    setCustomValidity(message) {
        if (this.isButton()) {
            this.button.setCustomValidity(message);
            this.formControlController.updateValidity();
        }
    }
    render() {
        const isLink = this.isLink();
        const tag = isLink ? literal `a` : literal `button`;
        const variantCaretColors = {
            primary: this.disabled ? 'var(--nile-colors-white-base, var(--ng-colors-fg-disabled-subtle))' : 'var(--nile-colors-white-base, var(--ng-componentcolors-components-button-primary-icon))',
            secondary: this.disabled ? 'var(--nile-colors-dark-500, var(--ng-colors-fg-disabled-subtle))' : 'var(--nile-colors-dark-900, var(--ng-colors-fg-quaternary-400))',
            tertiary: this.disabled ? 'var(--nile-colors-neutral-500, var(--ng-colors-fg-disabled-subtle))' : 'var(--nile-colors-dark-900, var(--ng-colors-fg-quaternary-400))',
            caution: this.disabled ? 'var(--nile-colors-white-base, var(--ng-colors-fg-disabled-subtle))' : 'var(--nile-colors-white-base)',
            ghost: this.disabled ? 'var(--nile-colors-neutral-500, var(--ng-colors-fg-disabled-subtle))' : 'var(--nile-colors-dark-900, var(--ng-colors-fg-quaternary-400))',
            destructive: this.disabled ? 'var(--nile-colors-white-base, var(--ng-colors-fg-disabled-subtle))' : 'var(--nile-colors-white-base, var(--ng-componentcolors-components-button-destructive-primary-icon))',
            'secondary-grey': 'black',
            'secondary-blue': 'black',
            'tertiary-blue': 'black',
        };
        if (this.isLink()) {
            return html `
        <a
          part="base"
          class=${classMap({
                button: true,
                'button--primary': this.variant === 'primary',
                'button--secondary': this.variant === 'secondary',
                'button--tertiary': this.variant === 'tertiary',
                'button--caution': this.variant === 'caution',
                'button--ghost': this.variant === 'ghost',
                'button--destructive': this.variant === 'destructive',
                'button--secondary-grey': this.variant === 'secondary-grey',
                'button--secondary-blue': this.variant === 'secondary-blue',
                'button--hideborder': this.hideBorder,
                'button--medium': this.size === 'medium',
                'button--caret': this.caret,
                'button--circle': this.circle,
                'button--disabled': this.disabled,
                'button--focused': this.hasFocus,
                'button--loading': this.loading,
                'button--standard': !this.outline,
                'button--outline': this.outline,
                'button--pill': this.pill,
                'button--has-label': this.hasSlotController.test('[default]'),
                'button--has-prefix': this.hasSlotController.test('prefix'),
                'button--has-suffix': this.hasSlotController.test('suffix'),
            })}
          href=${ifDefined(this.href)}
          target=${ifDefined(this.target)}
          download=${ifDefined(this.download)}
          rel=${ifDefined(this.rel)}
          title=${this.title}
          role="button"
          aria-disabled=${this.disabled ? 'true' : 'false'}
          tabindex=${this.disabled ? '-1' : '0'}
          @blur=${this.handleBlur}
          @focus=${this.handleFocus}
          @click=${this.handleClick}
        >
          <slot name="prefix" part="prefix" class="button__prefix"></slot>
          <slot part="label" class="button__label"></slot>
          <slot name="suffix" part="suffix" class="button__suffix"></slot>
          ${this.caret
                ? html `
                <nile-icon
                  part="caret"
                  class="button__caret"
                  color="${variantCaretColors[this.variant]}"
                  name="var(--nile-icon-arrow-down, var(--ng-icon-chevron-down))"
                  method="var(--nile-svg-method-fill, var(--ng-svg-method-stroke))"
                ></nile-icon>
              `
                : ''}
          ${this.loading ? html `<nile-spinner></nile-spinner>` : ''}
        </a>
      `;
        }
        else {
            return html `
      <button
        part="base"
        class=${classMap({
                button: true,
                'button--primary': this.variant === 'primary',
                'button--secondary': this.variant === 'secondary',
                'button--tertiary': this.variant === 'tertiary',
                'button--caution': this.variant === 'caution',
                'button--ghost': this.variant === 'ghost',
                'button--destructive': this.variant === 'destructive',
                'button--secondary-grey': this.variant === 'secondary-grey',
                'button--secondary-blue': this.variant === 'secondary-blue',
                'button--hideborder': this.hideBorder,
                'button--medium': this.size === 'medium',
                'button--caret': this.caret,
                'button--circle': this.circle,
                'button--disabled': this.disabled,
                'button--focused': this.hasFocus,
                'button--loading': this.loading,
                'button--standard': !this.outline,
                'button--outline': this.outline,
                'button--pill': this.pill,
                'button--has-label': this.hasSlotController.test('[default]'),
                'button--has-prefix': this.hasSlotController.test('prefix'),
                'button--has-suffix': this.hasSlotController.test('suffix'),
            })}
        ?disabled=${this.disabled}
        type=${this.type}
        name=${ifDefined(this.name)}
        value=${ifDefined(this.value)}
        title=${this.title}
        aria-disabled=${this.disabled ? 'true' : 'false'}
        tabindex=${this.disabled ? '-1' : '0'}
        @blur=${this.handleBlur}
        @focus=${this.handleFocus}
        @invalid=${this.handleInvalid}
        @click=${this.handleClick}
      >
        <slot name="prefix" part="prefix" class="button__prefix"></slot>
        <slot part="label" class="button__label"></slot>
        <slot name="suffix" part="suffix" class="button__suffix"></slot>
        ${this.caret
                ? html `
              <nile-icon
                part="caret"
                class="button__caret"
                color=${variantCaretColors[this.variant]}
                name="var(--nile-icon-arrow-down, var(--ng-icon-chevron-down))"
                method="var(--nile-svg-method-fill, var(--ng-svg-method-stroke))"
              ></nile-icon>
            `
                : ''}
        ${this.loading ? html `<nile-spinner></nile-spinner>` : ''}
      </button>
    `;
        }
    }
};
NileButton.styles = styles;
__decorate([
    query('.button')
], NileButton.prototype, "button", void 0);
__decorate([
    state()
], NileButton.prototype, "hasFocus", void 0);
__decorate([
    state()
], NileButton.prototype, "invalid", void 0);
__decorate([
    property()
], NileButton.prototype, "title", void 0);
__decorate([
    property({ reflect: true })
], NileButton.prototype, "variant", void 0);
__decorate([
    state()
], NileButton.prototype, "size", void 0);
__decorate([
    property({ type: Boolean, reflect: true })
], NileButton.prototype, "caret", void 0);
__decorate([
    property({ type: Boolean, reflect: true })
], NileButton.prototype, "disabled", void 0);
__decorate([
    property({ type: Boolean, reflect: true })
], NileButton.prototype, "loading", void 0);
__decorate([
    property({ type: Boolean, reflect: true })
], NileButton.prototype, "outline", void 0);
__decorate([
    property({ type: Boolean, reflect: true })
], NileButton.prototype, "pill", void 0);
__decorate([
    property({ type: Boolean, reflect: true })
], NileButton.prototype, "circle", void 0);
__decorate([
    property()
], NileButton.prototype, "type", void 0);
__decorate([
    property()
], NileButton.prototype, "name", void 0);
__decorate([
    property()
], NileButton.prototype, "value", void 0);
__decorate([
    property()
], NileButton.prototype, "href", void 0);
__decorate([
    property()
], NileButton.prototype, "target", void 0);
__decorate([
    property()
], NileButton.prototype, "rel", void 0);
__decorate([
    property()
], NileButton.prototype, "download", void 0);
__decorate([
    property()
], NileButton.prototype, "form", void 0);
__decorate([
    property({ attribute: 'formaction' })
], NileButton.prototype, "formAction", void 0);
__decorate([
    property({ attribute: 'formenctype' })
], NileButton.prototype, "formEnctype", void 0);
__decorate([
    property({ attribute: 'formmethod' })
], NileButton.prototype, "formMethod", void 0);
__decorate([
    property({ attribute: 'formnovalidate', type: Boolean })
], NileButton.prototype, "formNoValidate", void 0);
__decorate([
    property({ attribute: 'formtarget' })
], NileButton.prototype, "formTarget", void 0);
__decorate([
    property({ type: Boolean, reflect: true, attribute: 'hide-border' })
], NileButton.prototype, "hideBorder", void 0);
__decorate([
    watch('disabled', { waitUntilFirstUpdate: true })
], NileButton.prototype, "handleDisabledChange", null);
NileButton = __decorate([
    customElement('nile-button')
], NileButton);
export { NileButton };
export default NileButton;
//# sourceMappingURL=nile-button.js.map