import { Build, Component, Element, Method, Prop, State, h } from '@stencil/core';
import { closestElementCrossShadowBoundary, mapGet, queryElementRoots } from '../../utils';
/**
 * Passing a 'href' will render an anchor link, instead of a button. Role will
 * be set to link, or button, depending on this. It is the consumers
 * responsibility to add aria information, rel, target, for links, and any
 * button attributes for form submission.
 *
 * @slot default text slot for button text.
 */
export class Button {
  constructor() {
    //--------------------------------------------------------------------------
    //
    //  Props
    //
    //--------------------------------------------------------------------------
    /**
     * Provides an outlined appearance (i.e. solid border) to the button.
     * Currently, only brand and destructive variants support outline.
     */
    this.appearance = 'solid';
    /** Disables button interaction. */
    this.disabled = false;
    /** Sets button color. */
    this.palette = 'brand';
    /** Sets anchor target attribute. */
    this.target = '_self';
    /** Sets button width. */
    this.width = 'auto';
    /** rendered child element node type */
    this.childElType = 'button';
    this.updateHasContent = () => {
      var _a, _b;
      const slottedContent = this.host.textContent.trim().length > 0 || this.host.childNodes.length > 0;
      this.hasContent =
        this.host.childNodes.length === 1 && ((_a = this.host.childNodes[0]) === null || _a === void 0 ? void 0 : _a.nodeName) === '#text'
          ? ((_b = this.host.textContent) === null || _b === void 0 ? void 0 : _b.trim().length) > 0
          : slottedContent;
    };
    //--------------------------------------------------------------------------
    //
    //  Private State
    //
    //--------------------------------------------------------------------------
    /** Determine if slotted content is present for styling purposes. */
    this.hasContent = false;
  }
  //--------------------------------------------------------------------------
  //
  //  Private Methods
  //
  //--------------------------------------------------------------------------
  // Act on requested or nearby form based on type.
  handleClick(event) {
    const { buttonType } = this;
    const { tagName } = event.currentTarget;
    // Set focus on click to workaround Safari issue on OX X 10.X.
    // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#clicking_and_focus
    this.setFocus();
    // this.buttonType refers to type attribute, not child element type
    if (tagName === 'BUTTON' && buttonType !== 'button') {
      event.preventDefault();
      const { formId, host } = this;
      const targetForm = formId
        ? queryElementRoots(host, `#${formId}`)
        : closestElementCrossShadowBoundary(host, 'form');
      if (targetForm) {
        const targetFormSubmitFunction = targetForm.onsubmit;
        const eventTypeHandlers = {
          reset: () => {
            targetForm.reset();
          },
          submit: () => {
            if (targetFormSubmitFunction)
              targetFormSubmitFunction();
            else if (targetForm.checkValidity())
              targetForm.submit();
            else
              targetForm.reportValidity();
          },
        };
        const eventTypeHandler = mapGet(buttonType, eventTypeHandlers);
        typeof eventTypeHandler === 'function' && eventTypeHandler();
      }
    }
  }
  //--------------------------------------------------------------------------
  //
  //  Public Methods
  //
  //--------------------------------------------------------------------------
  /** Sets focus on child element. */
  async setFocus() {
    const { childEl } = this;
    childEl.focus();
  }
  //--------------------------------------------------------------------------
  //
  //  Lifecycle Methods
  //
  //--------------------------------------------------------------------------
  componentWillLoad() {
    if (Build.isBrowser) {
      const { buttonType, childElType, updateHasContent } = this;
      updateHasContent();
      if (childElType === 'button' && buttonType !== '')
        this.buttonType = 'submit';
    }
  }
  componentWillRender() {
    const { href } = this;
    this.childElType = href ? 'a' : 'button';
  }
  connectedCallback() {
    const setupTextContentObserver = () => {
      if (Build.isBrowser) {
        this.observer = new MutationObserver(() => {
          this.updateHasContent();
        });
        this.observer.observe(this.host, { childList: true, subtree: true });
      }
    };
    this.handleClick = this.handleClick.bind(this);
    setupTextContentObserver();
  }
  disconnectedCallback() {
    const { observer } = this;
    observer.disconnect();
  }
  render() {
    const { buttonType, childElType: Tag, disabled, hasContent, href, iconEnd, iconStart, label, name, handleClick, rel, target, } = this;
    return (h(Tag, { "aria-label": label, disabled: disabled, href: href, name: Tag === 'button' && name, onClick: !disabled && handleClick, ref: (element) => {
        if (element)
          this.childEl = element;
      }, rel: Tag === 'a' && rel, tabIndex: disabled ? -1 : null, target: Tag === 'a' && target, type: Tag === 'button' && (buttonType || 'button') },
      iconStart && h("abds-icon", { icon: iconStart, size: "md", "stroke-width": "bold" }),
      hasContent && h("slot", null),
      iconEnd && h("abds-icon", { icon: iconEnd, size: "md", "stroke-width": "bold" })));
  }
  static get is() { return "abds-button"; }
  static get encapsulation() { return "shadow"; }
  static get originalStyleUrls() { return {
    "$": ["button.css"]
  }; }
  static get styleUrls() { return {
    "$": ["button.css"]
  }; }
  static get properties() { return {
    "appearance": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "ButtonAppearance",
        "resolved": "\"outline\" | \"solid\" | \"transparent\"",
        "references": {
          "ButtonAppearance": {
            "location": "import",
            "path": "./types"
          }
        }
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Provides an outlined appearance (i.e. solid border) to the button.\nCurrently, only brand and destructive variants support outline."
      },
      "attribute": "appearance",
      "reflect": true,
      "defaultValue": "'solid'"
    },
    "buttonType": {
      "type": "string",
      "mutable": true,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Sets button type attribute; defaults to **button** if not specified."
      },
      "attribute": "button-type",
      "reflect": false
    },
    "disabled": {
      "type": "boolean",
      "mutable": false,
      "complexType": {
        "original": "boolean",
        "resolved": "boolean",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Disables button interaction."
      },
      "attribute": "disabled",
      "reflect": true,
      "defaultValue": "false"
    },
    "formId": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Form ID associated with component."
      },
      "attribute": "form-id",
      "reflect": false
    },
    "href": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Sets anchor href attribute; determines if component should render as anchor or button."
      },
      "attribute": "href",
      "reflect": true
    },
    "iconEnd": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Adds an abds-icon to end of button text."
      },
      "attribute": "icon-end",
      "reflect": true
    },
    "iconStart": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Adds an abds-icon to beginning of button text."
      },
      "attribute": "icon-start",
      "reflect": true
    },
    "label": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Sets aria-label attribute on anchor or button."
      },
      "attribute": "label",
      "reflect": false
    },
    "name": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Sets button name attribute."
      },
      "attribute": "name",
      "reflect": false
    },
    "palette": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "ButtonPalette",
        "resolved": "\"brand\" | \"destructive\" | \"inverse\" | \"neutral\" | \"success\"",
        "references": {
          "ButtonPalette": {
            "location": "import",
            "path": "./types"
          }
        }
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Sets button color."
      },
      "attribute": "palette",
      "reflect": true,
      "defaultValue": "'brand'"
    },
    "rel": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Sets anchor rel attribute."
      },
      "attribute": "rel",
      "reflect": false
    },
    "target": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "ButtonTarget",
        "resolved": "\"_blank\" | \"_parent\" | \"_self\" | \"_top\"",
        "references": {
          "ButtonTarget": {
            "location": "import",
            "path": "./types"
          }
        }
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Sets anchor target attribute."
      },
      "attribute": "target",
      "reflect": false,
      "defaultValue": "'_self'"
    },
    "width": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "Width",
        "resolved": "\"auto\" | \"full\"",
        "references": {
          "Width": {
            "location": "import",
            "path": "../types"
          }
        }
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Sets button width."
      },
      "attribute": "width",
      "reflect": true,
      "defaultValue": "'auto'"
    }
  }; }
  static get states() { return {
    "hasContent": {}
  }; }
  static get methods() { return {
    "setFocus": {
      "complexType": {
        "signature": "() => Promise<void>",
        "parameters": [],
        "references": {
          "Promise": {
            "location": "global"
          }
        },
        "return": "Promise<void>"
      },
      "docs": {
        "text": "Sets focus on child element.",
        "tags": []
      }
    }
  }; }
  static get elementRef() { return "host"; }
}
//# sourceMappingURL=button.js.map