{"version":3,"sources":["../src/elements/password.ts","../src/styles/elements/password.ts"],"sourcesContent":["import { html, LitElement, TemplateResult } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { emitEvent } from '../utilities/events';\nimport KemetField from './field';\nimport KemetInput from './input';\nimport { EnumStatuses, TypeStatus } from '../utilities/constants';\nimport KemetTextarea from './textarea';\nimport { stylesBase } from '../styles/elements/password';\nimport './icon-bootstrap';\n\n\n/**\n * @since 1.2.0\n * @status stable\n *\n * @tagname kemet-password\n * @summary Gauges the strength of a password entered by the user.\n *\n * @prop {array} rules - An array of objects containing the rules the password must meet.\n * @prop {boolean} show - Controls the display of the component.\n * @prop {string} value - The value of the input component.\n * @prop {string} message - A message that is above the rules.\n * @prop {string} strength - The strength of the password. Weak | Better | Strong.\n * @prop {string} icon\n * @prop {number} iconSize\n *\n * @event kemet-status-change - Fires when there's a change in status.\n *\n * @csspart status - The status message.\n * @csspart indicator - The strength indicator bars.\n * @csspart message - A message to display to the user.\n * @csspart rules - A description of rules to follow.\n *\n */\n\ninterface InterfaceOptions {\n  pattern: string;\n  message: string;\n  meetsCriteria?: boolean;\n}\n\nexport interface InterfacePasswordStatusChangeDetails {\n  status: TypeStatus;\n  meetsPasswordCriteria: boolean;\n  element: KemetPassword;\n}\n\n@customElement('kemet-password')\nexport default class KemetPassword extends LitElement {\n  static styles = [stylesBase];\n\n  @property({ type: Array })\n  rules: InterfaceOptions[] = [\n    { pattern: '(?=.{8,}$)', message: 'At least 8 characters long' },\n    { pattern: '(?=.*[a-z])(?=.*[A-Z])', message: 'Uppercase and lowercase' },\n    { pattern: '(?=.*[0-9])', message: 'At least one number (0-9)' },\n  ];\n\n  @property({ type: Boolean, reflect: true })\n  show: boolean;\n\n  @property({ type: String })\n  value: string;\n\n  @property({ type: String })\n  message: string = 'Please make sure you meet all the requirements.';\n\n  @property({ type: String })\n  strength: string;\n\n  @property({ type: String })\n  icon: string = 'check2';\n\n  @property({ type: Number })\n  iconSize: number = 18;\n\n  @state()\n  status: TypeStatus;\n\n  @state()\n  field: KemetField;\n\n  @state()\n  input: KemetInput | KemetTextarea;\n\n  firstUpdated() {\n    // elements\n    this.field = this.closest('kemet-field');\n    this.input = this.field.querySelector('[slot=\"input\"]');\n\n    // events listeners\n    this.input.addEventListener('kemet-input', this.handleInput.bind(this));\n  }\n\n  render() {\n    return html`\n      <div role=\"alert\" aria-live=\"assertive\">\n        <div class=\"status status--${this.strength}\" part=\"status\">\n          <span>${this.strength}</span>\n          <ul class=\"indicator\" part=\"indicator\">\n            <li></li>\n            <li></li>\n            <li></li>\n          </ul>\n        </div>\n        <p class=\"message\" part=\"message\">${this.message}</p>\n        <ul class=\"rules\" part=\"rules\">\n          ${this.makeRules()}\n        </ul>\n      </div>\n    `;\n  }\n\n  /**\n   * Makes the list of rules\n   * @private\n   * @returns {TemplateResult<1>[]} the criteria rules\n   */\n  makeRules(): TemplateResult<1>[] {\n    if (this.input) {\n      return this.rules.map((rule, index) => {\n        const regExp = new RegExp(rule.pattern);\n        const meetsCriteria = regExp.test(this.input.value);\n        this.rules[index].meetsCriteria = meetsCriteria;\n        return html`<li>${this.makeCheckIcon(meetsCriteria)} ${rule.message}</li>`;\n      });\n    }\n\n    return null;\n  }\n\n  /**\n   * Makes the check icon if the criteria has been met\n   * @param {boolean} meetsCriteria\n   * @private\n   * @returns {TemplateResult} an icon component\n   */\n  makeCheckIcon(meetsCriteria: boolean): TemplateResult {\n    if (meetsCriteria) {\n      return html`<kemet-icon-bootstrap icon=${this.icon} size=${this.iconSize}></kemet-icon-bootstrap>`;\n    }\n\n    return null;\n  }\n\n  /**\n   * Handles the kemet-input-input event\n   * @param {*} event\n   * @private\n   */\n  handleInput(event: CustomEvent) {\n    this.value = event.detail.value;\n    this.setStrength();\n    this.visibility();\n  }\n\n  /**\n   * Determines the strength of the password\n   * @private\n   */\n  setStrength() {\n    // We use a setTimeout here because makeRules adds the meetsCriteria\n    // property to the rules. We need that to be set by render() before\n    // setting the Strength because the percentage calc is based on it\n    setTimeout(() => {\n      const totalRules = this.rules.length;\n      const metRules = this.rules.filter(rule => rule.meetsCriteria).length;\n      const metRulesPercentage = Math.round((metRules / totalRules) * 100) / 100;\n\n      if (metRulesPercentage <= 0.33) {\n        this.strength = 'weak';\n        this.status = EnumStatuses.Error;\n      }\n\n      if (metRulesPercentage > 0.33 && metRulesPercentage <= 0.67) {\n        this.strength = 'better';\n        this.status = EnumStatuses.Error;\n      }\n\n      if (metRulesPercentage > 0.67) {\n        this.strength = 'strong';\n        this.status = EnumStatuses.Success;\n      }\n\n      emitEvent(this, 'kemet-status-change', {\n        status: this.status,\n        meetsPasswordCriteria: this.status === EnumStatuses.Success,\n        element: this,\n      });\n    }, 1);\n  }\n\n  /**\n   * Determines whether to show or hide the component\n   * @private\n   */\n  visibility() {\n    this.show = this.value.length > 0;\n  }\n}\n\ndeclare global {\n  interface HTMLElementTagNameMap {\n    'kemet-password': KemetPassword\n  }\n}\n","import { css } from 'lit';\n\nexport const stylesBase = css`\n  :host {\n    color: inherit;\n    display: none;\n  }\n\n  :host([show]) {\n    display: block;\n  }\n\n  p {\n    margin: 1.6rem 0;\n  }\n\n  .status {\n    display: grid;\n    align-items: center;\n    grid-template-columns: 1fr auto;\n    line-height: 1;\n    margin-top: 0.8rem;\n  }\n\n  .status > span {\n    text-transform: capitalize;\n  }\n\n  .status--weak,\n  .status--better {\n    color: rgb(var(--kemet-color-error));\n  }\n\n  .status--strong {\n    color: rgb(var(--kemet-color-success));\n  }\n\n  .indicator {\n    display: flex;\n    gap: 0.4rem;\n    margin: 0;\n    list-style: none;\n  }\n\n  .indicator li {\n    width: 1.6rem;\n    height: 0.2rem;\n  }\n\n  .status--weak .indicator li:nth-child(1) {\n    background-color: rgb(var(--kemet-color-error));\n  }\n\n  .status--better .indicator li:nth-child(1),\n  .status--better .indicator li:nth-child(2) {\n    background-color: rgb(var(--kemet-color-error));\n  }\n\n  .status--strong .indicator li {\n    background-color: rgb(var(--kemet-color-success));\n  }\n\n  .rules {\n    color: rgb(var(--kemet-color-foreground));\n    line-height: 1.5;\n    list-style: none;\n    font-size: 90%;\n    padding-left: 2rem;\n  }\n\n  .rules li {\n    position: relative;\n  }\n\n  .rules kemet-icon-bootstrap {\n    color: rgb(var(--kemet-color-success));\n    position: absolute;\n    left: -2rem;\n  }\n`;\n"],"mappings":"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","names":[]}