import { Component, Element, Event, h, Listen, Method, Prop } from '@stencil/core';
import { serialize } from '../../../functions/form';
export class ScForm {
  constructor() {
    /** Prevent the form from validating inputs before submitting. */
    this.novalidate = false;
  }
  /** Serializes all form controls elements and returns a `FormData` object. */
  async getFormData() {
    return new FormData(this.formElement);
  }
  async getFormJson() {
    return serialize(this.formElement);
  }
  async handleChange() {
    this.scFormChange.emit(serialize(this.formElement));
  }
  async submit() {
    return this.submitForm();
  }
  /** Gets all form control elements (native and custom). */
  getFormControls() {
    return [...this.form.querySelectorAll('*')];
  }
  async validate() {
    const formControls = this.getFormControls();
    const formControlsThatReport = formControls.filter((el) => typeof el.reportValidity === 'function');
    if (!this.novalidate) {
      for (const el of formControlsThatReport) {
        const isValid = await el.reportValidity();
        if (!isValid) {
          return false;
        }
      }
    }
    return true;
  }
  submitForm() {
    // Calling form.submit() seems to bypass the submit event and constraint validation. Instead, we can inject a
    // native submit button into the form, click it, then remove it to simulate a standard form submission.
    const button = document.createElement('button');
    if (this.formElement) {
      button.type = 'submit';
      button.style.position = 'absolute';
      button.style.width = '0';
      button.style.height = '0';
      button.style.clip = 'rect(0 0 0 0)';
      button.style.clipPath = 'inset(50%)';
      button.style.overflow = 'hidden';
      button.style.whiteSpace = 'nowrap';
      this.formElement.append(button);
      button.click();
      button.remove();
    }
  }
  render() {
    return (h("div", { part: "base", class: "form", role: "form" },
      h("form", { ref: el => (this.formElement = el), onSubmit: async (e) => {
          e.preventDefault();
          const isValid = await this.validate();
          if (!isValid) {
            return false;
          }
          this.scSubmit.emit();
          this.scFormSubmit.emit();
        }, novalidate: this.novalidate },
        h("slot", null))));
  }
  static get is() { return "sc-form"; }
  static get encapsulation() { return "shadow"; }
  static get originalStyleUrls() { return {
    "$": ["sc-form.scss"]
  }; }
  static get styleUrls() { return {
    "$": ["sc-form.css"]
  }; }
  static get properties() { return {
    "novalidate": {
      "type": "boolean",
      "mutable": true,
      "complexType": {
        "original": "boolean",
        "resolved": "boolean",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Prevent the form from validating inputs before submitting."
      },
      "attribute": "novalidate",
      "reflect": true,
      "defaultValue": "false"
    }
  }; }
  static get events() { return [{
      "method": "scSubmit",
      "name": "scSubmit",
      "bubbles": true,
      "cancelable": true,
      "composed": true,
      "docs": {
        "tags": [],
        "text": "Emitted when the form is submitted. This event will not be emitted if any form control inside of\nit is in an invalid state, unless the form has the `novalidate` attribute. Note that there is never a need to prevent\nthis event, since it doen't send a GET or POST request like native forms. To \"prevent\" submission, use a conditional\naround the XHR request you use to submit the form's data with."
      },
      "complexType": {
        "original": "void",
        "resolved": "void",
        "references": {}
      }
    }, {
      "method": "scFormSubmit",
      "name": "scFormSubmit",
      "bubbles": true,
      "cancelable": true,
      "composed": true,
      "docs": {
        "tags": [],
        "text": "Backwards compat."
      },
      "complexType": {
        "original": "void",
        "resolved": "void",
        "references": {}
      }
    }, {
      "method": "scFormChange",
      "name": "scFormChange",
      "bubbles": true,
      "cancelable": true,
      "composed": true,
      "docs": {
        "tags": [],
        "text": "Emitted when the form is submitted. This event will not be emitted if any form control inside of\nit is in an invalid state, unless the form has the `novalidate` attribute. Note that there is never a need to prevent\nthis event, since it doen't send a GET or POST request like native forms. To \"prevent\" submission, use a conditional\naround the XHR request you use to submit the form's data with."
      },
      "complexType": {
        "original": "Object",
        "resolved": "Object",
        "references": {
          "Object": {
            "location": "global"
          }
        }
      }
    }]; }
  static get methods() { return {
    "getFormData": {
      "complexType": {
        "signature": "() => Promise<FormData>",
        "parameters": [],
        "references": {
          "Promise": {
            "location": "global"
          },
          "FormData": {
            "location": "global"
          }
        },
        "return": "Promise<FormData>"
      },
      "docs": {
        "text": "Serializes all form controls elements and returns a `FormData` object.",
        "tags": []
      }
    },
    "getFormJson": {
      "complexType": {
        "signature": "() => Promise<Record<string, unknown>>",
        "parameters": [],
        "references": {
          "Promise": {
            "location": "global"
          },
          "Record": {
            "location": "global"
          }
        },
        "return": "Promise<Record<string, unknown>>"
      },
      "docs": {
        "text": "",
        "tags": []
      }
    },
    "submit": {
      "complexType": {
        "signature": "() => Promise<void>",
        "parameters": [],
        "references": {
          "Promise": {
            "location": "global"
          }
        },
        "return": "Promise<void>"
      },
      "docs": {
        "text": "",
        "tags": []
      }
    },
    "validate": {
      "complexType": {
        "signature": "() => Promise<boolean>",
        "parameters": [],
        "references": {
          "Promise": {
            "location": "global"
          }
        },
        "return": "Promise<boolean>"
      },
      "docs": {
        "text": "",
        "tags": []
      }
    }
  }; }
  static get elementRef() { return "form"; }
  static get listeners() { return [{
      "name": "scChange",
      "method": "handleChange",
      "target": undefined,
      "capture": false,
      "passive": false
    }]; }
}
