{"version":3,"file":"password-input.mjs","sources":["../../../../src/govuk/components/password-input/password-input.mjs"],"sourcesContent":["import { closestAttributeValue } from '../../common/closest-attribute-value.mjs'\nimport { ConfigurableComponent } from '../../common/configuration.mjs'\nimport { ElementError } from '../../errors/index.mjs'\nimport { I18n } from '../../i18n.mjs'\n\n/**\n * Password input component\n *\n * @preserve\n * @augments ConfigurableComponent<PasswordInputConfig>\n */\nexport class PasswordInput extends ConfigurableComponent {\n  /** @private */\n  i18n\n\n  /**\n   * @private\n   * @type {HTMLInputElement}\n   */\n  $input\n\n  /**\n   * @private\n   * @type {HTMLButtonElement}\n   */\n  $showHideButton\n\n  /** @private */\n  $screenReaderStatusMessage\n\n  /**\n   * @param {Element | null} $root - HTML element to use for password input\n   * @param {PasswordInputConfig} [config] - Password input config\n   */\n  constructor($root, config = {}) {\n    super($root, config)\n\n    const $input = this.$root.querySelector('.govuk-js-password-input-input')\n    if (!($input instanceof HTMLInputElement)) {\n      throw new ElementError({\n        component: PasswordInput,\n        element: $input,\n        expectedType: 'HTMLInputElement',\n        identifier: 'Form field (`.govuk-js-password-input-input`)'\n      })\n    }\n\n    if ($input.type !== 'password') {\n      throw new ElementError(\n        'Password input: Form field (`.govuk-js-password-input-input`) must be of type `password`.'\n      )\n    }\n\n    const $showHideButton = this.$root.querySelector(\n      '.govuk-js-password-input-toggle'\n    )\n    if (!($showHideButton instanceof HTMLButtonElement)) {\n      throw new ElementError({\n        component: PasswordInput,\n        element: $showHideButton,\n        expectedType: 'HTMLButtonElement',\n        identifier: 'Button (`.govuk-js-password-input-toggle`)'\n      })\n    }\n\n    if ($showHideButton.type !== 'button') {\n      throw new ElementError(\n        'Password input: Button (`.govuk-js-password-input-toggle`) must be of type `button`.'\n      )\n    }\n\n    this.$input = $input\n    this.$showHideButton = $showHideButton\n\n    this.i18n = new I18n(this.config.i18n, {\n      // Read the fallback if necessary rather than have it set in the defaults\n      locale: closestAttributeValue(this.$root, 'lang')\n    })\n\n    // Show the toggle button element\n    this.$showHideButton.removeAttribute('hidden')\n\n    // Create and append the status text for screen readers.\n    // This is injected between the input and button so that users get a sensible reading order if\n    // moving through the page content linearly:\n    // [password input] -> [your password is visible/hidden] -> [show/hide password]\n    const $screenReaderStatusMessage = document.createElement('div')\n    $screenReaderStatusMessage.className =\n      'govuk-password-input__sr-status govuk-visually-hidden'\n    $screenReaderStatusMessage.setAttribute('aria-live', 'polite')\n    this.$screenReaderStatusMessage = $screenReaderStatusMessage\n    this.$input.insertAdjacentElement('afterend', $screenReaderStatusMessage)\n\n    // Bind toggle button\n    this.$showHideButton.addEventListener('click', this.toggle.bind(this))\n\n    // Bind event to revert the password visibility to hidden\n    if (this.$input.form) {\n      this.$input.form.addEventListener('submit', () => this.hide())\n    }\n\n    // If the page is restored from bfcache and the password is visible, hide it again\n    window.addEventListener('pageshow', (event) => {\n      if (event.persisted && this.$input.type !== 'password') {\n        this.hide()\n      }\n    })\n\n    // Default the component to having the password hidden.\n    this.hide()\n  }\n\n  /**\n   * Toggle the visibility of the password input\n   *\n   * @private\n   * @param {MouseEvent} event - Click event\n   */\n  toggle(event) {\n    event.preventDefault()\n\n    // If on this click, the field is type=\"password\", show the value\n    if (this.$input.type === 'password') {\n      this.show()\n      return\n    }\n\n    // Otherwise, hide it\n    // Being defensive - hiding should always be the default\n    this.hide()\n  }\n\n  /**\n   * Show the password input value in plain text.\n   *\n   * @private\n   */\n  show() {\n    this.setType('text')\n  }\n\n  /**\n   * Hide the password input value.\n   *\n   * @private\n   */\n  hide() {\n    this.setType('password')\n  }\n\n  /**\n   * Set the password input type\n   *\n   * @param {'text' | 'password'} type - Input type\n   * @private\n   */\n  setType(type) {\n    if (type === this.$input.type) {\n      return\n    }\n\n    // Update input type\n    this.$input.setAttribute('type', type)\n\n    const isHidden = type === 'password'\n    const prefixButton = isHidden ? 'show' : 'hide'\n    const prefixStatus = isHidden ? 'passwordHidden' : 'passwordShown'\n\n    // Update button text\n    this.$showHideButton.innerText = this.i18n.t(`${prefixButton}Password`)\n\n    // Update button aria-label\n    this.$showHideButton.setAttribute(\n      'aria-label',\n      this.i18n.t(`${prefixButton}PasswordAriaLabel`)\n    )\n\n    // Update status change text\n    this.$screenReaderStatusMessage.innerText = this.i18n.t(\n      `${prefixStatus}Announcement`\n    )\n  }\n\n  /**\n   * Name for the component used when initialising using data-module attributes.\n   */\n  static moduleName = 'govuk-password-input'\n\n  /**\n   * Password input default config\n   *\n   * @see {@link PasswordInputConfig}\n   * @constant\n   * @default\n   * @type {PasswordInputConfig}\n   */\n  static defaults = Object.freeze({\n    i18n: {\n      showPassword: 'Show',\n      hidePassword: 'Hide',\n      showPasswordAriaLabel: 'Show password',\n      hidePasswordAriaLabel: 'Hide password',\n      passwordShownAnnouncement: 'Your password is visible',\n      passwordHiddenAnnouncement: 'Your password is hidden'\n    }\n  })\n\n  /**\n   * Password input config schema\n   *\n   * @constant\n   * @satisfies {Schema<PasswordInputConfig>}\n   */\n  static schema = Object.freeze({\n    properties: {\n      i18n: { type: 'object' }\n    }\n  })\n}\n\n/**\n * Password input config\n *\n * @typedef {object} PasswordInputConfig\n * @property {PasswordInputTranslations} [i18n=PasswordInput.defaults.i18n] - Password input translations\n */\n\n/**\n * Password input translations\n *\n * @see {@link PasswordInput.defaults.i18n}\n * @typedef {object} PasswordInputTranslations\n *\n * Messages displayed to the user indicating the state of the show/hide toggle.\n * @property {string} [showPassword] - Visible text of the button when the\n *   password is currently hidden. Plain text only.\n * @property {string} [hidePassword] - Visible text of the button when the\n *   password is currently visible. Plain text only.\n * @property {string} [showPasswordAriaLabel] - aria-label of the button when\n *   the password is currently hidden. Plain text only.\n * @property {string} [hidePasswordAriaLabel] - aria-label of the button when\n *   the password is currently visible. Plain text only.\n * @property {string} [passwordShownAnnouncement] - Screen reader\n *   announcement to make when the password has just become visible.\n *   Plain text only.\n * @property {string} [passwordHiddenAnnouncement] - Screen reader\n *   announcement to make when the password has just been hidden.\n *   Plain text only.\n */\n\n/**\n * @import { Schema } from '../../common/configuration.mjs'\n */\n"],"names":["PasswordInput","ConfigurableComponent","constructor","$root","config","i18n","$input","$showHideButton","$screenReaderStatusMessage","querySelector","HTMLInputElement","ElementError","component","element","expectedType","identifier","type","HTMLButtonElement","I18n","locale","closestAttributeValue","removeAttribute","document","createElement","className","setAttribute","insertAdjacentElement","addEventListener","toggle","bind","form","hide","window","event","persisted","preventDefault","show","setType","isHidden","prefixButton","prefixStatus","innerText","t","moduleName","defaults","Object","freeze","showPassword","hidePassword","showPasswordAriaLabel","hidePasswordAriaLabel","passwordShownAnnouncement","passwordHiddenAnnouncement","schema","properties"],"mappings":";;;;;AAKA;AACA;AACA;AACA;AACA;AACA;AACO,MAAMA,aAAa,SAASC,qBAAqB,CAAC;AAmBvD;AACF;AACA;AACA;AACEC,EAAAA,WAAWA,CAACC,KAAK,EAAEC,MAAM,GAAG,EAAE,EAAE;AAC9B,IAAA,KAAK,CAACD,KAAK,EAAEC,MAAM,CAAC;AAAA,IAAA,IAAA,CAtBtBC,IAAI,GAAA,MAAA;AAAA,IAAA,IAAA,CAMJC,MAAM,GAAA,MAAA;AAAA,IAAA,IAAA,CAMNC,eAAe,GAAA,MAAA;AAAA,IAAA,IAAA,CAGfC,0BAA0B,GAAA,MAAA;IASxB,MAAMF,MAAM,GAAG,IAAI,CAACH,KAAK,CAACM,aAAa,CAAC,gCAAgC,CAAC;AACzE,IAAA,IAAI,EAAEH,MAAM,YAAYI,gBAAgB,CAAC,EAAE;MACzC,MAAM,IAAIC,YAAY,CAAC;AACrBC,QAAAA,SAAS,EAAEZ,aAAa;AACxBa,QAAAA,OAAO,EAAEP,MAAM;AACfQ,QAAAA,YAAY,EAAE,kBAAkB;AAChCC,QAAAA,UAAU,EAAE;AACd,OAAC,CAAC;AACJ,IAAA;AAEA,IAAA,IAAIT,MAAM,CAACU,IAAI,KAAK,UAAU,EAAE;AAC9B,MAAA,MAAM,IAAIL,YAAY,CACpB,2FACF,CAAC;AACH,IAAA;IAEA,MAAMJ,eAAe,GAAG,IAAI,CAACJ,KAAK,CAACM,aAAa,CAC9C,iCACF,CAAC;AACD,IAAA,IAAI,EAAEF,eAAe,YAAYU,iBAAiB,CAAC,EAAE;MACnD,MAAM,IAAIN,YAAY,CAAC;AACrBC,QAAAA,SAAS,EAAEZ,aAAa;AACxBa,QAAAA,OAAO,EAAEN,eAAe;AACxBO,QAAAA,YAAY,EAAE,mBAAmB;AACjCC,QAAAA,UAAU,EAAE;AACd,OAAC,CAAC;AACJ,IAAA;AAEA,IAAA,IAAIR,eAAe,CAACS,IAAI,KAAK,QAAQ,EAAE;AACrC,MAAA,MAAM,IAAIL,YAAY,CACpB,sFACF,CAAC;AACH,IAAA;IAEA,IAAI,CAACL,MAAM,GAAGA,MAAM;IACpB,IAAI,CAACC,eAAe,GAAGA,eAAe;IAEtC,IAAI,CAACF,IAAI,GAAG,IAAIa,IAAI,CAAC,IAAI,CAACd,MAAM,CAACC,IAAI,EAAE;AAErCc,MAAAA,MAAM,EAAEC,qBAAqB,CAAC,IAAI,CAACjB,KAAK,EAAE,MAAM;AAClD,KAAC,CAAC;AAGF,IAAA,IAAI,CAACI,eAAe,CAACc,eAAe,CAAC,QAAQ,CAAC;AAM9C,IAAA,MAAMb,0BAA0B,GAAGc,QAAQ,CAACC,aAAa,CAAC,KAAK,CAAC;IAChEf,0BAA0B,CAACgB,SAAS,GAClC,uDAAuD;AACzDhB,IAAAA,0BAA0B,CAACiB,YAAY,CAAC,WAAW,EAAE,QAAQ,CAAC;IAC9D,IAAI,CAACjB,0BAA0B,GAAGA,0BAA0B;IAC5D,IAAI,CAACF,MAAM,CAACoB,qBAAqB,CAAC,UAAU,EAAElB,0BAA0B,CAAC;AAGzE,IAAA,IAAI,CAACD,eAAe,CAACoB,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAACC,MAAM,CAACC,IAAI,CAAC,IAAI,CAAC,CAAC;AAGtE,IAAA,IAAI,IAAI,CAACvB,MAAM,CAACwB,IAAI,EAAE;AACpB,MAAA,IAAI,CAACxB,MAAM,CAACwB,IAAI,CAACH,gBAAgB,CAAC,QAAQ,EAAE,MAAM,IAAI,CAACI,IAAI,EAAE,CAAC;AAChE,IAAA;AAGAC,IAAAA,MAAM,CAACL,gBAAgB,CAAC,UAAU,EAAGM,KAAK,IAAK;MAC7C,IAAIA,KAAK,CAACC,SAAS,IAAI,IAAI,CAAC5B,MAAM,CAACU,IAAI,KAAK,UAAU,EAAE;QACtD,IAAI,CAACe,IAAI,EAAE;AACb,MAAA;AACF,IAAA,CAAC,CAAC;IAGF,IAAI,CAACA,IAAI,EAAE;AACb,EAAA;EAQAH,MAAMA,CAACK,KAAK,EAAE;IACZA,KAAK,CAACE,cAAc,EAAE;AAGtB,IAAA,IAAI,IAAI,CAAC7B,MAAM,CAACU,IAAI,KAAK,UAAU,EAAE;MACnC,IAAI,CAACoB,IAAI,EAAE;AACX,MAAA;AACF,IAAA;IAIA,IAAI,CAACL,IAAI,EAAE;AACb,EAAA;AAOAK,EAAAA,IAAIA,GAAG;AACL,IAAA,IAAI,CAACC,OAAO,CAAC,MAAM,CAAC;AACtB,EAAA;AAOAN,EAAAA,IAAIA,GAAG;AACL,IAAA,IAAI,CAACM,OAAO,CAAC,UAAU,CAAC;AAC1B,EAAA;EAQAA,OAAOA,CAACrB,IAAI,EAAE;AACZ,IAAA,IAAIA,IAAI,KAAK,IAAI,CAACV,MAAM,CAACU,IAAI,EAAE;AAC7B,MAAA;AACF,IAAA;IAGA,IAAI,CAACV,MAAM,CAACmB,YAAY,CAAC,MAAM,EAAET,IAAI,CAAC;AAEtC,IAAA,MAAMsB,QAAQ,GAAGtB,IAAI,KAAK,UAAU;AACpC,IAAA,MAAMuB,YAAY,GAAGD,QAAQ,GAAG,MAAM,GAAG,MAAM;AAC/C,IAAA,MAAME,YAAY,GAAGF,QAAQ,GAAG,gBAAgB,GAAG,eAAe;AAGlE,IAAA,IAAI,CAAC/B,eAAe,CAACkC,SAAS,GAAG,IAAI,CAACpC,IAAI,CAACqC,CAAC,CAAC,CAAA,EAAGH,YAAY,UAAU,CAAC;AAGvE,IAAA,IAAI,CAAChC,eAAe,CAACkB,YAAY,CAC/B,YAAY,EACZ,IAAI,CAACpB,IAAI,CAACqC,CAAC,CAAC,GAAGH,YAAY,CAAA,iBAAA,CAAmB,CAChD,CAAC;AAGD,IAAA,IAAI,CAAC/B,0BAA0B,CAACiC,SAAS,GAAG,IAAI,CAACpC,IAAI,CAACqC,CAAC,CACrD,CAAA,EAAGF,YAAY,cACjB,CAAC;AACH,EAAA;AAqCF;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AAjPaxC,aAAa,CA+KjB2C,UAAU,GAAG,sBAAsB;AA/K/B3C,aAAa,CAyLjB4C,QAAQ,GAAGC,MAAM,CAACC,MAAM,CAAC;AAC9BzC,EAAAA,IAAI,EAAE;AACJ0C,IAAAA,YAAY,EAAE,MAAM;AACpBC,IAAAA,YAAY,EAAE,MAAM;AACpBC,IAAAA,qBAAqB,EAAE,eAAe;AACtCC,IAAAA,qBAAqB,EAAE,eAAe;AACtCC,IAAAA,yBAAyB,EAAE,0BAA0B;AACrDC,IAAAA,0BAA0B,EAAE;AAC9B;AACF,CAAC,CAAC;AAlMSpD,aAAa,CA0MjBqD,MAAM,GAAGR,MAAM,CAACC,MAAM,CAAC;AAC5BQ,EAAAA,UAAU,EAAE;AACVjD,IAAAA,IAAI,EAAE;AAAEW,MAAAA,IAAI,EAAE;AAAS;AACzB;AACF,CAAC,CAAC;;;;"}