govuk_publishing_components 51.1.0 → 51.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/stylesheets/component_guide/application.scss +1 -1
  3. data/app/assets/stylesheets/govuk_publishing_components/_all_components.scss +1 -0
  4. data/app/assets/stylesheets/govuk_publishing_components/components/_metadata.scss +3 -19
  5. data/app/assets/stylesheets/govuk_publishing_components/components/helpers/_markdown-typography.scss +1 -0
  6. data/app/models/govuk_publishing_components/audit_comparer.rb +3 -3
  7. data/app/views/govuk_publishing_components/components/_title.html.erb +2 -3
  8. data/app/views/govuk_publishing_components/components/docs/add_another.yml +1 -1
  9. data/app/views/govuk_publishing_components/components/docs/big_number.yml +1 -0
  10. data/lib/govuk_publishing_components/presenters/checkboxes_helper.rb +1 -1
  11. data/lib/govuk_publishing_components/presenters/shared_helper.rb +0 -11
  12. data/lib/govuk_publishing_components/version.rb +1 -1
  13. data/node_modules/govuk-frontend/dist/govuk/all.bundle.js +217 -184
  14. data/node_modules/govuk-frontend/dist/govuk/all.bundle.js.map +1 -1
  15. data/node_modules/govuk-frontend/dist/govuk/all.bundle.mjs +216 -184
  16. data/node_modules/govuk-frontend/dist/govuk/all.bundle.mjs.map +1 -1
  17. data/node_modules/govuk-frontend/dist/govuk/all.mjs +1 -0
  18. data/node_modules/govuk-frontend/dist/govuk/all.mjs.map +1 -1
  19. data/node_modules/govuk-frontend/dist/govuk/all.scss +6 -0
  20. data/node_modules/govuk-frontend/dist/govuk/all.scss.map +1 -1
  21. data/node_modules/govuk-frontend/dist/govuk/common/configuration.mjs +164 -0
  22. data/node_modules/govuk-frontend/dist/govuk/common/configuration.mjs.map +1 -0
  23. data/node_modules/govuk-frontend/dist/govuk/common/govuk-frontend-version.mjs +1 -1
  24. data/node_modules/govuk-frontend/dist/govuk/common/index.mjs +1 -87
  25. data/node_modules/govuk-frontend/dist/govuk/common/index.mjs.map +1 -1
  26. data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.js +149 -112
  27. data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.js.map +1 -1
  28. data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.mjs +148 -111
  29. data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.bundle.mjs.map +1 -1
  30. data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.mjs +5 -8
  31. data/node_modules/govuk-frontend/dist/govuk/components/accordion/accordion.mjs.map +1 -1
  32. data/node_modules/govuk-frontend/dist/govuk/components/button/button.bundle.js +149 -112
  33. data/node_modules/govuk-frontend/dist/govuk/components/button/button.bundle.js.map +1 -1
  34. data/node_modules/govuk-frontend/dist/govuk/components/button/button.bundle.mjs +148 -111
  35. data/node_modules/govuk-frontend/dist/govuk/components/button/button.bundle.mjs.map +1 -1
  36. data/node_modules/govuk-frontend/dist/govuk/components/button/button.mjs +5 -8
  37. data/node_modules/govuk-frontend/dist/govuk/components/button/button.mjs.map +1 -1
  38. data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.js +174 -140
  39. data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.js.map +1 -1
  40. data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.mjs +173 -139
  41. data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.bundle.mjs.map +1 -1
  42. data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.mjs +17 -16
  43. data/node_modules/govuk-frontend/dist/govuk/components/character-count/character-count.mjs.map +1 -1
  44. data/node_modules/govuk-frontend/dist/govuk/components/character-count/macro-options.json +4 -4
  45. data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.js +1 -24
  46. data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.js.map +1 -1
  47. data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.mjs +0 -23
  48. data/node_modules/govuk-frontend/dist/govuk/components/checkboxes/checkboxes.bundle.mjs.map +1 -1
  49. data/node_modules/govuk-frontend/dist/govuk/components/date-input/macro-options.json +2 -2
  50. data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.js +149 -112
  51. data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.js.map +1 -1
  52. data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.mjs +148 -111
  53. data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.bundle.mjs.map +1 -1
  54. data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.mjs +6 -8
  55. data/node_modules/govuk-frontend/dist/govuk/components/error-summary/error-summary.mjs.map +1 -1
  56. data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.js +149 -112
  57. data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.js.map +1 -1
  58. data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.mjs +148 -111
  59. data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.bundle.mjs.map +1 -1
  60. data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.mjs +5 -8
  61. data/node_modules/govuk-frontend/dist/govuk/components/exit-this-page/exit-this-page.mjs.map +1 -1
  62. data/node_modules/govuk-frontend/dist/govuk/components/header/header.bundle.js +1 -24
  63. data/node_modules/govuk-frontend/dist/govuk/components/header/header.bundle.js.map +1 -1
  64. data/node_modules/govuk-frontend/dist/govuk/components/header/header.bundle.mjs +0 -23
  65. data/node_modules/govuk-frontend/dist/govuk/components/header/header.bundle.mjs.map +1 -1
  66. data/node_modules/govuk-frontend/dist/govuk/components/input/macro-options.json +4 -4
  67. data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.js +149 -112
  68. data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.js.map +1 -1
  69. data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.mjs +148 -111
  70. data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.bundle.mjs.map +1 -1
  71. data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.mjs +6 -8
  72. data/node_modules/govuk-frontend/dist/govuk/components/notification-banner/notification-banner.mjs.map +1 -1
  73. data/node_modules/govuk-frontend/dist/govuk/components/password-input/macro-options.json +1 -1
  74. data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.js +149 -112
  75. data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.js.map +1 -1
  76. data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.mjs +148 -111
  77. data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.bundle.mjs.map +1 -1
  78. data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.mjs +5 -8
  79. data/node_modules/govuk-frontend/dist/govuk/components/password-input/password-input.mjs.map +1 -1
  80. data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.bundle.js +1 -24
  81. data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.bundle.js.map +1 -1
  82. data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.bundle.mjs +0 -23
  83. data/node_modules/govuk-frontend/dist/govuk/components/radios/radios.bundle.mjs.map +1 -1
  84. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.js +1 -24
  85. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.js.map +1 -1
  86. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.mjs +0 -23
  87. data/node_modules/govuk-frontend/dist/govuk/components/service-navigation/service-navigation.bundle.mjs.map +1 -1
  88. data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.js +1 -24
  89. data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.js.map +1 -1
  90. data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.mjs +0 -23
  91. data/node_modules/govuk-frontend/dist/govuk/components/skip-link/skip-link.bundle.mjs.map +1 -1
  92. data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.js +1 -24
  93. data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.js.map +1 -1
  94. data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.mjs +0 -23
  95. data/node_modules/govuk-frontend/dist/govuk/components/tabs/tabs.bundle.mjs.map +1 -1
  96. data/node_modules/govuk-frontend/dist/govuk/components/textarea/macro-options.json +1 -1
  97. data/node_modules/govuk-frontend/dist/govuk/core/_govuk-frontend-properties.scss +1 -1
  98. data/node_modules/govuk-frontend/dist/govuk/govuk-frontend.min.css +1 -1
  99. data/node_modules/govuk-frontend/dist/govuk/govuk-frontend.min.css.map +1 -1
  100. data/node_modules/govuk-frontend/dist/govuk/govuk-frontend.min.js +1 -1
  101. data/node_modules/govuk-frontend/dist/govuk/govuk-frontend.min.js.map +1 -1
  102. data/node_modules/govuk-frontend/dist/govuk/init.mjs +17 -13
  103. data/node_modules/govuk-frontend/dist/govuk/init.mjs.map +1 -1
  104. data/node_modules/govuk-frontend/dist/govuk/settings/_typography-responsive.scss +5 -10
  105. data/node_modules/govuk-frontend/dist/govuk/settings/_typography-responsive.scss.map +1 -1
  106. data/node_modules/govuk-frontend/govuk-prototype-kit.config.json +1 -1
  107. data/node_modules/govuk-frontend/package.json +9 -9
  108. metadata +4 -6
  109. data/node_modules/govuk-frontend/dist/govuk/common/normalise-dataset.mjs +0 -18
  110. data/node_modules/govuk-frontend/dist/govuk/common/normalise-dataset.mjs.map +0 -1
  111. data/node_modules/govuk-frontend/dist/govuk/common/normalise-string.mjs +0 -31
  112. data/node_modules/govuk-frontend/dist/govuk/common/normalise-string.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"character-count.mjs","sources":["../../../../src/govuk/components/character-count/character-count.mjs"],"sourcesContent":["import { closestAttributeValue } from '../../common/closest-attribute-value.mjs'\nimport {\n formatErrorMessage,\n mergeConfigs,\n validateConfig\n} from '../../common/index.mjs'\nimport { normaliseDataset } from '../../common/normalise-dataset.mjs'\nimport { ConfigError, ElementError } from '../../errors/index.mjs'\nimport { GOVUKFrontendComponent } from '../../govuk-frontend-component.mjs'\nimport { I18n } from '../../i18n.mjs'\n\n/**\n * Character count component\n *\n * Tracks the number of characters or words in the `.govuk-js-character-count`\n * `<textarea>` inside the element. Displays a message with the remaining number\n * of characters/words available, or the number of characters/words in excess.\n *\n * You can configure the message to only appear after a certain percentage\n * of the available characters/words has been entered.\n *\n * @preserve\n */\nexport class CharacterCount extends GOVUKFrontendComponent {\n /** @private */\n $textarea\n\n /** @private */\n $visibleCountMessage\n\n /** @private */\n $screenReaderCountMessage\n\n /**\n * @private\n * @type {number | null}\n */\n lastInputTimestamp = null\n\n /** @private */\n lastInputValue = ''\n\n /**\n * @private\n * @type {number | null}\n */\n valueChecker = null\n\n /**\n * @private\n * @type {CharacterCountConfig}\n */\n config\n\n /** @private */\n i18n\n\n /** @private */\n maxLength\n\n /**\n * @param {Element | null} $root - HTML element to use for character count\n * @param {CharacterCountConfig} [config] - Character count config\n */\n constructor($root, config = {}) {\n super($root)\n\n const $textarea = this.$root.querySelector('.govuk-js-character-count')\n if (\n !(\n $textarea instanceof HTMLTextAreaElement ||\n $textarea instanceof HTMLInputElement\n )\n ) {\n throw new ElementError({\n component: CharacterCount,\n element: $textarea,\n expectedType: 'HTMLTextareaElement or HTMLInputElement',\n identifier: 'Form field (`.govuk-js-character-count`)'\n })\n }\n\n // Read config set using dataset ('data-' values)\n const datasetConfig = normaliseDataset(CharacterCount, this.$root.dataset)\n\n // To ensure data-attributes take complete precedence, even if they change\n // the type of count, we need to reset the `maxlength` and `maxwords` from\n // the JavaScript config.\n //\n // We can't mutate `config`, though, as it may be shared across multiple\n // components inside `initAll`.\n /** @type {CharacterCountConfig} */\n let configOverrides = {}\n if ('maxwords' in datasetConfig || 'maxlength' in datasetConfig) {\n configOverrides = {\n maxlength: undefined,\n maxwords: undefined\n }\n }\n\n this.config = mergeConfigs(\n CharacterCount.defaults,\n config,\n configOverrides,\n datasetConfig\n )\n\n // Check for valid config\n const errors = validateConfig(CharacterCount.schema, this.config)\n if (errors[0]) {\n throw new ConfigError(formatErrorMessage(CharacterCount, errors[0]))\n }\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 // Determine the limit attribute (characters or words)\n this.maxLength = this.config.maxwords ?? this.config.maxlength ?? Infinity\n\n this.$textarea = $textarea\n\n const textareaDescriptionId = `${this.$textarea.id}-info`\n const $textareaDescription = document.getElementById(textareaDescriptionId)\n if (!$textareaDescription) {\n throw new ElementError({\n component: CharacterCount,\n element: $textareaDescription,\n identifier: `Count message (\\`id=\"${textareaDescriptionId}\"\\`)`\n })\n }\n\n // Inject a description for the textarea if none is present already\n // for when the component was rendered with no maxlength, maxwords\n // nor custom textareaDescriptionText\n if (`${$textareaDescription.textContent}`.match(/^\\s*$/)) {\n $textareaDescription.textContent = this.i18n.t('textareaDescription', {\n count: this.maxLength\n })\n }\n\n // Move the textarea description to be immediately after the textarea\n // Kept for backwards compatibility\n this.$textarea.insertAdjacentElement('afterend', $textareaDescription)\n\n // Create the *screen reader* specific live-updating counter\n // This doesn't need any styling classes, as it is never visible\n const $screenReaderCountMessage = document.createElement('div')\n $screenReaderCountMessage.className =\n 'govuk-character-count__sr-status govuk-visually-hidden'\n $screenReaderCountMessage.setAttribute('aria-live', 'polite')\n this.$screenReaderCountMessage = $screenReaderCountMessage\n $textareaDescription.insertAdjacentElement(\n 'afterend',\n $screenReaderCountMessage\n )\n\n // Create our live-updating counter element, copying the classes from the\n // textarea description for backwards compatibility as these may have been\n // configured\n const $visibleCountMessage = document.createElement('div')\n $visibleCountMessage.className = $textareaDescription.className\n $visibleCountMessage.classList.add('govuk-character-count__status')\n $visibleCountMessage.setAttribute('aria-hidden', 'true')\n this.$visibleCountMessage = $visibleCountMessage\n $textareaDescription.insertAdjacentElement('afterend', $visibleCountMessage)\n\n // Hide the textarea description\n $textareaDescription.classList.add('govuk-visually-hidden')\n\n // Remove hard limit if set\n this.$textarea.removeAttribute('maxlength')\n\n this.bindChangeEvents()\n\n // When the page is restored after navigating 'back' in some browsers the\n // state of form controls is not restored until *after* the DOMContentLoaded\n // event is fired, so we need to sync after the pageshow event.\n window.addEventListener('pageshow', () => this.updateCountMessage())\n\n // Although we've set up handlers to sync state on the pageshow event, init\n // could be called after those events have fired, for example if they are\n // added to the page dynamically, so update now too.\n this.updateCountMessage()\n }\n\n /**\n * Bind change events\n *\n * Set up event listeners on the $textarea so that the count messages update\n * when the user types.\n *\n * @private\n */\n bindChangeEvents() {\n this.$textarea.addEventListener('keyup', () => this.handleKeyUp())\n\n // Bind focus/blur events to start/stop polling\n this.$textarea.addEventListener('focus', () => this.handleFocus())\n this.$textarea.addEventListener('blur', () => this.handleBlur())\n }\n\n /**\n * Handle key up event\n *\n * Update the visible character counter and keep track of when the last update\n * happened for each keypress\n *\n * @private\n */\n handleKeyUp() {\n this.updateVisibleCountMessage()\n this.lastInputTimestamp = Date.now()\n }\n\n /**\n * Handle focus event\n *\n * Speech recognition software such as Dragon NaturallySpeaking will modify\n * the fields by directly changing its `value`. These changes don't trigger\n * events in JavaScript, so we need to poll to handle when and if they occur.\n *\n * Once the keyup event hasn't been detected for at least 1000 ms (1s), check\n * if the textarea value has changed and update the count message if it has.\n *\n * This is so that the update triggered by the manual comparison doesn't\n * conflict with debounced KeyboardEvent updates.\n *\n * @private\n */\n handleFocus() {\n this.valueChecker = window.setInterval(() => {\n if (\n !this.lastInputTimestamp ||\n Date.now() - 500 >= this.lastInputTimestamp\n ) {\n this.updateIfValueChanged()\n }\n }, 1000)\n }\n\n /**\n * Handle blur event\n *\n * Stop checking the textarea value once the textarea no longer has focus\n *\n * @private\n */\n handleBlur() {\n // Cancel value checking on blur\n if (this.valueChecker) {\n window.clearInterval(this.valueChecker)\n }\n }\n\n /**\n * Update count message if textarea value has changed\n *\n * @private\n */\n updateIfValueChanged() {\n if (this.$textarea.value !== this.lastInputValue) {\n this.lastInputValue = this.$textarea.value\n this.updateCountMessage()\n }\n }\n\n /**\n * Update count message\n *\n * Helper function to update both the visible and screen reader-specific\n * counters simultaneously (e.g. on init)\n *\n * @private\n */\n updateCountMessage() {\n this.updateVisibleCountMessage()\n this.updateScreenReaderCountMessage()\n }\n\n /**\n * Update visible count message\n *\n * @private\n */\n updateVisibleCountMessage() {\n const remainingNumber = this.maxLength - this.count(this.$textarea.value)\n const isError = remainingNumber < 0\n\n // If input is over the threshold, remove the disabled class which renders\n // the counter invisible.\n this.$visibleCountMessage.classList.toggle(\n 'govuk-character-count__message--disabled',\n !this.isOverThreshold()\n )\n\n // Update styles\n this.$textarea.classList.toggle('govuk-textarea--error', isError)\n this.$visibleCountMessage.classList.toggle('govuk-error-message', isError)\n this.$visibleCountMessage.classList.toggle('govuk-hint', !isError)\n\n // Update message\n this.$visibleCountMessage.textContent = this.getCountMessage()\n }\n\n /**\n * Update screen reader count message\n *\n * @private\n */\n updateScreenReaderCountMessage() {\n // If over the threshold, remove the aria-hidden attribute, allowing screen\n // readers to announce the content of the element.\n if (this.isOverThreshold()) {\n this.$screenReaderCountMessage.removeAttribute('aria-hidden')\n } else {\n this.$screenReaderCountMessage.setAttribute('aria-hidden', 'true')\n }\n\n // Update message\n this.$screenReaderCountMessage.textContent = this.getCountMessage()\n }\n\n /**\n * Count the number of characters (or words, if `config.maxwords` is set)\n * in the given text\n *\n * @private\n * @param {string} text - The text to count the characters of\n * @returns {number} the number of characters (or words) in the text\n */\n count(text) {\n if (this.config.maxwords) {\n const tokens = text.match(/\\S+/g) ?? [] // Matches consecutive non-whitespace chars\n return tokens.length\n }\n\n return text.length\n }\n\n /**\n * Get count message\n *\n * @private\n * @returns {string} Status message\n */\n getCountMessage() {\n const remainingNumber = this.maxLength - this.count(this.$textarea.value)\n const countType = this.config.maxwords ? 'words' : 'characters'\n return this.formatCountMessage(remainingNumber, countType)\n }\n\n /**\n * Formats the message shown to users according to what's counted\n * and how many remain\n *\n * @private\n * @param {number} remainingNumber - The number of words/characaters remaining\n * @param {string} countType - \"words\" or \"characters\"\n * @returns {string} Status message\n */\n formatCountMessage(remainingNumber, countType) {\n if (remainingNumber === 0) {\n return this.i18n.t(`${countType}AtLimit`)\n }\n\n const translationKeySuffix =\n remainingNumber < 0 ? 'OverLimit' : 'UnderLimit'\n\n return this.i18n.t(`${countType}${translationKeySuffix}`, {\n count: Math.abs(remainingNumber)\n })\n }\n\n /**\n * Check if count is over threshold\n *\n * Checks whether the value is over the configured threshold for the input.\n * If there is no configured threshold, it is set to 0 and this function will\n * always return true.\n *\n * @private\n * @returns {boolean} true if the current count is over the config.threshold\n * (or no threshold is set)\n */\n isOverThreshold() {\n // No threshold means we're always above threshold so save some computation\n if (!this.config.threshold) {\n return true\n }\n\n // Determine the remaining number of characters/words\n const currentLength = this.count(this.$textarea.value)\n const maxLength = this.maxLength\n\n const thresholdValue = (maxLength * this.config.threshold) / 100\n\n return thresholdValue <= currentLength\n }\n\n /**\n * Name for the component used when initialising using data-module attributes.\n */\n static moduleName = 'govuk-character-count'\n\n /**\n * Character count default config\n *\n * @see {@link CharacterCountConfig}\n * @constant\n * @type {CharacterCountConfig}\n */\n static defaults = Object.freeze({\n threshold: 0,\n i18n: {\n // Characters\n charactersUnderLimit: {\n one: 'You have %{count} character remaining',\n other: 'You have %{count} characters remaining'\n },\n charactersAtLimit: 'You have 0 characters remaining',\n charactersOverLimit: {\n one: 'You have %{count} character too many',\n other: 'You have %{count} characters too many'\n },\n // Words\n wordsUnderLimit: {\n one: 'You have %{count} word remaining',\n other: 'You have %{count} words remaining'\n },\n wordsAtLimit: 'You have 0 words remaining',\n wordsOverLimit: {\n one: 'You have %{count} word too many',\n other: 'You have %{count} words too many'\n },\n textareaDescription: {\n other: ''\n }\n }\n })\n\n /**\n * Character count config schema\n *\n * @constant\n * @satisfies {Schema}\n */\n static schema = Object.freeze({\n properties: {\n i18n: { type: 'object' },\n maxwords: { type: 'number' },\n maxlength: { type: 'number' },\n threshold: { type: 'number' }\n },\n anyOf: [\n {\n required: ['maxwords'],\n errorMessage: 'Either \"maxlength\" or \"maxwords\" must be provided'\n },\n {\n required: ['maxlength'],\n errorMessage: 'Either \"maxlength\" or \"maxwords\" must be provided'\n }\n ]\n })\n}\n\n/**\n * Character count config\n *\n * @see {@link CharacterCount.defaults}\n * @typedef {object} CharacterCountConfig\n * @property {number} [maxlength] - The maximum number of characters.\n * If maxwords is provided, the maxlength option will be ignored.\n * @property {number} [maxwords] - The maximum number of words. If maxwords is\n * provided, the maxlength option will be ignored.\n * @property {number} [threshold=0] - The percentage value of the limit at\n * which point the count message is displayed. If this attribute is set, the\n * count message will be hidden by default.\n * @property {CharacterCountTranslations} [i18n=CharacterCount.defaults.i18n] - Character count translations\n */\n\n/**\n * Character count translations\n *\n * @see {@link CharacterCount.defaults.i18n}\n * @typedef {object} CharacterCountTranslations\n *\n * Messages shown to users as they type. It provides feedback on how many words\n * or characters they have remaining or if they are over the limit. This also\n * includes a message used as an accessible description for the textarea.\n * @property {TranslationPluralForms} [charactersUnderLimit] - Message displayed\n * when the number of characters is under the configured maximum, `maxlength`.\n * This message is displayed visually and through assistive technologies. The\n * component will replace the `%{count}` placeholder with the number of\n * remaining characters. This is a [pluralised list of\n * messages](https://frontend.design-system.service.gov.uk/localise-govuk-frontend).\n * @property {string} [charactersAtLimit] - Message displayed when the number of\n * characters reaches the configured maximum, `maxlength`. This message is\n * displayed visually and through assistive technologies.\n * @property {TranslationPluralForms} [charactersOverLimit] - Message displayed\n * when the number of characters is over the configured maximum, `maxlength`.\n * This message is displayed visually and through assistive technologies. The\n * component will replace the `%{count}` placeholder with the number of\n * remaining characters. This is a [pluralised list of\n * messages](https://frontend.design-system.service.gov.uk/localise-govuk-frontend).\n * @property {TranslationPluralForms} [wordsUnderLimit] - Message displayed when\n * the number of words is under the configured maximum, `maxlength`. This\n * message is displayed visually and through assistive technologies. The\n * component will replace the `%{count}` placeholder with the number of\n * remaining words. This is a [pluralised list of\n * messages](https://frontend.design-system.service.gov.uk/localise-govuk-frontend).\n * @property {string} [wordsAtLimit] - Message displayed when the number of\n * words reaches the configured maximum, `maxlength`. This message is\n * displayed visually and through assistive technologies.\n * @property {TranslationPluralForms} [wordsOverLimit] - Message displayed when\n * the number of words is over the configured maximum, `maxlength`. This\n * message is displayed visually and through assistive technologies. The\n * component will replace the `%{count}` placeholder with the number of\n * remaining words. This is a [pluralised list of\n * messages](https://frontend.design-system.service.gov.uk/localise-govuk-frontend).\n * @property {TranslationPluralForms} [textareaDescription] - Message made\n * available to assistive technologies, if none is already present in the\n * HTML, to describe that the component accepts only a limited amount of\n * content. It is visible on the page when JavaScript is unavailable. The\n * component will replace the `%{count}` placeholder with the value of the\n * `maxlength` or `maxwords` parameter.\n */\n\n/**\n * @typedef {import('../../common/index.mjs').Schema} Schema\n * @typedef {import('../../i18n.mjs').TranslationPluralForms} TranslationPluralForms\n */\n"],"names":["CharacterCount","GOVUKFrontendComponent","constructor","$root","config","_ref","_this$config$maxwords","$textarea","$visibleCountMessage","$screenReaderCountMessage","lastInputTimestamp","lastInputValue","valueChecker","i18n","maxLength","querySelector","HTMLTextAreaElement","HTMLInputElement","ElementError","component","element","expectedType","identifier","datasetConfig","normaliseDataset","dataset","configOverrides","maxlength","undefined","maxwords","mergeConfigs","defaults","errors","validateConfig","schema","ConfigError","formatErrorMessage","I18n","locale","closestAttributeValue","Infinity","textareaDescriptionId","id","$textareaDescription","document","getElementById","textContent","match","t","count","insertAdjacentElement","createElement","className","setAttribute","classList","add","removeAttribute","bindChangeEvents","window","addEventListener","updateCountMessage","handleKeyUp","handleFocus","handleBlur","updateVisibleCountMessage","Date","now","setInterval","updateIfValueChanged","clearInterval","value","updateScreenReaderCountMessage","remainingNumber","isError","toggle","isOverThreshold","getCountMessage","text","_text$match","tokens","length","countType","formatCountMessage","translationKeySuffix","Math","abs","threshold","currentLength","thresholdValue","moduleName","Object","freeze","charactersUnderLimit","one","other","charactersAtLimit","charactersOverLimit","wordsUnderLimit","wordsAtLimit","wordsOverLimit","textareaDescription","properties","type","anyOf","required","errorMessage"],"mappings":"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"}
1
+ {"version":3,"file":"character-count.mjs","sources":["../../../../src/govuk/components/character-count/character-count.mjs"],"sourcesContent":["import { closestAttributeValue } from '../../common/closest-attribute-value.mjs'\nimport {\n validateConfig,\n ConfigurableComponent,\n configOverride\n} from '../../common/configuration.mjs'\nimport { formatErrorMessage } from '../../common/index.mjs'\nimport { ConfigError, ElementError } from '../../errors/index.mjs'\nimport { I18n } from '../../i18n.mjs'\n\n/**\n * Character count component\n *\n * Tracks the number of characters or words in the `.govuk-js-character-count`\n * `<textarea>` inside the element. Displays a message with the remaining number\n * of characters/words available, or the number of characters/words in excess.\n *\n * You can configure the message to only appear after a certain percentage\n * of the available characters/words has been entered.\n *\n * @preserve\n * @augments ConfigurableComponent<CharacterCountConfig>\n */\nexport class CharacterCount extends ConfigurableComponent {\n /** @private */\n $textarea\n\n /** @private */\n $visibleCountMessage\n\n /** @private */\n $screenReaderCountMessage\n\n /**\n * @private\n * @type {number | null}\n */\n lastInputTimestamp = null\n\n /** @private */\n lastInputValue = ''\n\n /**\n * @private\n * @type {number | null}\n */\n valueChecker = null\n\n /** @private */\n i18n\n\n /** @private */\n maxLength;\n\n /**\n * Character count config override\n *\n * To ensure data-attributes take complete precedence, even if they change\n * the type of count, we need to reset the `maxlength` and `maxwords` from\n * the JavaScript config.\n *\n * @internal\n * @param {CharacterCountConfig} datasetConfig - configuration specified by dataset\n * @returns {CharacterCountConfig} - configuration to override by dataset\n */\n [configOverride](datasetConfig) {\n let configOverrides = {}\n if ('maxwords' in datasetConfig || 'maxlength' in datasetConfig) {\n configOverrides = {\n maxlength: undefined,\n maxwords: undefined\n }\n }\n\n return configOverrides\n }\n\n /**\n * @param {Element | null} $root - HTML element to use for character count\n * @param {CharacterCountConfig} [config] - Character count config\n */\n constructor($root, config = {}) {\n super($root, config)\n\n const $textarea = this.$root.querySelector('.govuk-js-character-count')\n if (\n !(\n $textarea instanceof HTMLTextAreaElement ||\n $textarea instanceof HTMLInputElement\n )\n ) {\n throw new ElementError({\n component: CharacterCount,\n element: $textarea,\n expectedType: 'HTMLTextareaElement or HTMLInputElement',\n identifier: 'Form field (`.govuk-js-character-count`)'\n })\n }\n\n // Check for valid config\n const errors = validateConfig(CharacterCount.schema, this.config)\n if (errors[0]) {\n throw new ConfigError(formatErrorMessage(CharacterCount, errors[0]))\n }\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 // Determine the limit attribute (characters or words)\n this.maxLength = this.config.maxwords ?? this.config.maxlength ?? Infinity\n\n this.$textarea = $textarea\n\n const textareaDescriptionId = `${this.$textarea.id}-info`\n const $textareaDescription = document.getElementById(textareaDescriptionId)\n if (!$textareaDescription) {\n throw new ElementError({\n component: CharacterCount,\n element: $textareaDescription,\n identifier: `Count message (\\`id=\"${textareaDescriptionId}\"\\`)`\n })\n }\n\n // Inject a description for the textarea if none is present already\n // for when the component was rendered with no maxlength, maxwords\n // nor custom textareaDescriptionText\n if (`${$textareaDescription.textContent}`.match(/^\\s*$/)) {\n $textareaDescription.textContent = this.i18n.t('textareaDescription', {\n count: this.maxLength\n })\n }\n\n // Move the textarea description to be immediately after the textarea\n // Kept for backwards compatibility\n this.$textarea.insertAdjacentElement('afterend', $textareaDescription)\n\n // Create the *screen reader* specific live-updating counter\n // This doesn't need any styling classes, as it is never visible\n const $screenReaderCountMessage = document.createElement('div')\n $screenReaderCountMessage.className =\n 'govuk-character-count__sr-status govuk-visually-hidden'\n $screenReaderCountMessage.setAttribute('aria-live', 'polite')\n this.$screenReaderCountMessage = $screenReaderCountMessage\n $textareaDescription.insertAdjacentElement(\n 'afterend',\n $screenReaderCountMessage\n )\n\n // Create our live-updating counter element, copying the classes from the\n // textarea description for backwards compatibility as these may have been\n // configured\n const $visibleCountMessage = document.createElement('div')\n $visibleCountMessage.className = $textareaDescription.className\n $visibleCountMessage.classList.add('govuk-character-count__status')\n $visibleCountMessage.setAttribute('aria-hidden', 'true')\n this.$visibleCountMessage = $visibleCountMessage\n $textareaDescription.insertAdjacentElement('afterend', $visibleCountMessage)\n\n // Hide the textarea description\n $textareaDescription.classList.add('govuk-visually-hidden')\n\n // Remove hard limit if set\n this.$textarea.removeAttribute('maxlength')\n\n this.bindChangeEvents()\n\n // When the page is restored after navigating 'back' in some browsers the\n // state of form controls is not restored until *after* the DOMContentLoaded\n // event is fired, so we need to sync after the pageshow event.\n window.addEventListener('pageshow', () => this.updateCountMessage())\n\n // Although we've set up handlers to sync state on the pageshow event, init\n // could be called after those events have fired, for example if they are\n // added to the page dynamically, so update now too.\n this.updateCountMessage()\n }\n\n /**\n * Bind change events\n *\n * Set up event listeners on the $textarea so that the count messages update\n * when the user types.\n *\n * @private\n */\n bindChangeEvents() {\n this.$textarea.addEventListener('keyup', () => this.handleKeyUp())\n\n // Bind focus/blur events to start/stop polling\n this.$textarea.addEventListener('focus', () => this.handleFocus())\n this.$textarea.addEventListener('blur', () => this.handleBlur())\n }\n\n /**\n * Handle key up event\n *\n * Update the visible character counter and keep track of when the last update\n * happened for each keypress\n *\n * @private\n */\n handleKeyUp() {\n this.updateVisibleCountMessage()\n this.lastInputTimestamp = Date.now()\n }\n\n /**\n * Handle focus event\n *\n * Speech recognition software such as Dragon NaturallySpeaking will modify\n * the fields by directly changing its `value`. These changes don't trigger\n * events in JavaScript, so we need to poll to handle when and if they occur.\n *\n * Once the keyup event hasn't been detected for at least 1000 ms (1s), check\n * if the textarea value has changed and update the count message if it has.\n *\n * This is so that the update triggered by the manual comparison doesn't\n * conflict with debounced KeyboardEvent updates.\n *\n * @private\n */\n handleFocus() {\n this.valueChecker = window.setInterval(() => {\n if (\n !this.lastInputTimestamp ||\n Date.now() - 500 >= this.lastInputTimestamp\n ) {\n this.updateIfValueChanged()\n }\n }, 1000)\n }\n\n /**\n * Handle blur event\n *\n * Stop checking the textarea value once the textarea no longer has focus\n *\n * @private\n */\n handleBlur() {\n // Cancel value checking on blur\n if (this.valueChecker) {\n window.clearInterval(this.valueChecker)\n }\n }\n\n /**\n * Update count message if textarea value has changed\n *\n * @private\n */\n updateIfValueChanged() {\n if (this.$textarea.value !== this.lastInputValue) {\n this.lastInputValue = this.$textarea.value\n this.updateCountMessage()\n }\n }\n\n /**\n * Update count message\n *\n * Helper function to update both the visible and screen reader-specific\n * counters simultaneously (e.g. on init)\n *\n * @private\n */\n updateCountMessage() {\n this.updateVisibleCountMessage()\n this.updateScreenReaderCountMessage()\n }\n\n /**\n * Update visible count message\n *\n * @private\n */\n updateVisibleCountMessage() {\n const remainingNumber = this.maxLength - this.count(this.$textarea.value)\n const isError = remainingNumber < 0\n\n // If input is over the threshold, remove the disabled class which renders\n // the counter invisible.\n this.$visibleCountMessage.classList.toggle(\n 'govuk-character-count__message--disabled',\n !this.isOverThreshold()\n )\n\n // Update styles\n this.$textarea.classList.toggle('govuk-textarea--error', isError)\n this.$visibleCountMessage.classList.toggle('govuk-error-message', isError)\n this.$visibleCountMessage.classList.toggle('govuk-hint', !isError)\n\n // Update message\n this.$visibleCountMessage.textContent = this.getCountMessage()\n }\n\n /**\n * Update screen reader count message\n *\n * @private\n */\n updateScreenReaderCountMessage() {\n // If over the threshold, remove the aria-hidden attribute, allowing screen\n // readers to announce the content of the element.\n if (this.isOverThreshold()) {\n this.$screenReaderCountMessage.removeAttribute('aria-hidden')\n } else {\n this.$screenReaderCountMessage.setAttribute('aria-hidden', 'true')\n }\n\n // Update message\n this.$screenReaderCountMessage.textContent = this.getCountMessage()\n }\n\n /**\n * Count the number of characters (or words, if `config.maxwords` is set)\n * in the given text\n *\n * @private\n * @param {string} text - The text to count the characters of\n * @returns {number} the number of characters (or words) in the text\n */\n count(text) {\n if (this.config.maxwords) {\n const tokens = text.match(/\\S+/g) ?? [] // Matches consecutive non-whitespace chars\n return tokens.length\n }\n\n return text.length\n }\n\n /**\n * Get count message\n *\n * @private\n * @returns {string} Status message\n */\n getCountMessage() {\n const remainingNumber = this.maxLength - this.count(this.$textarea.value)\n const countType = this.config.maxwords ? 'words' : 'characters'\n return this.formatCountMessage(remainingNumber, countType)\n }\n\n /**\n * Formats the message shown to users according to what's counted\n * and how many remain\n *\n * @private\n * @param {number} remainingNumber - The number of words/characaters remaining\n * @param {string} countType - \"words\" or \"characters\"\n * @returns {string} Status message\n */\n formatCountMessage(remainingNumber, countType) {\n if (remainingNumber === 0) {\n return this.i18n.t(`${countType}AtLimit`)\n }\n\n const translationKeySuffix =\n remainingNumber < 0 ? 'OverLimit' : 'UnderLimit'\n\n return this.i18n.t(`${countType}${translationKeySuffix}`, {\n count: Math.abs(remainingNumber)\n })\n }\n\n /**\n * Check if count is over threshold\n *\n * Checks whether the value is over the configured threshold for the input.\n * If there is no configured threshold, it is set to 0 and this function will\n * always return true.\n *\n * @private\n * @returns {boolean} true if the current count is over the config.threshold\n * (or no threshold is set)\n */\n isOverThreshold() {\n // No threshold means we're always above threshold so save some computation\n if (!this.config.threshold) {\n return true\n }\n\n // Determine the remaining number of characters/words\n const currentLength = this.count(this.$textarea.value)\n const maxLength = this.maxLength\n\n const thresholdValue = (maxLength * this.config.threshold) / 100\n\n return thresholdValue <= currentLength\n }\n\n /**\n * Name for the component used when initialising using data-module attributes.\n */\n static moduleName = 'govuk-character-count'\n\n /**\n * Character count default config\n *\n * @see {@link CharacterCountConfig}\n * @constant\n * @type {CharacterCountConfig}\n */\n static defaults = Object.freeze({\n threshold: 0,\n i18n: {\n // Characters\n charactersUnderLimit: {\n one: 'You have %{count} character remaining',\n other: 'You have %{count} characters remaining'\n },\n charactersAtLimit: 'You have 0 characters remaining',\n charactersOverLimit: {\n one: 'You have %{count} character too many',\n other: 'You have %{count} characters too many'\n },\n // Words\n wordsUnderLimit: {\n one: 'You have %{count} word remaining',\n other: 'You have %{count} words remaining'\n },\n wordsAtLimit: 'You have 0 words remaining',\n wordsOverLimit: {\n one: 'You have %{count} word too many',\n other: 'You have %{count} words too many'\n },\n textareaDescription: {\n other: ''\n }\n }\n })\n\n /**\n * Character count config schema\n *\n * @constant\n * @satisfies {Schema}\n */\n static schema = Object.freeze({\n properties: {\n i18n: { type: 'object' },\n maxwords: { type: 'number' },\n maxlength: { type: 'number' },\n threshold: { type: 'number' }\n },\n anyOf: [\n {\n required: ['maxwords'],\n errorMessage: 'Either \"maxlength\" or \"maxwords\" must be provided'\n },\n {\n required: ['maxlength'],\n errorMessage: 'Either \"maxlength\" or \"maxwords\" must be provided'\n }\n ]\n })\n}\n\n/**\n * Character count config\n *\n * @see {@link CharacterCount.defaults}\n * @typedef {object} CharacterCountConfig\n * @property {number} [maxlength] - The maximum number of characters.\n * If maxwords is provided, the maxlength option will be ignored.\n * @property {number} [maxwords] - The maximum number of words. If maxwords is\n * provided, the maxlength option will be ignored.\n * @property {number} [threshold=0] - The percentage value of the limit at\n * which point the count message is displayed. If this attribute is set, the\n * count message will be hidden by default.\n * @property {CharacterCountTranslations} [i18n=CharacterCount.defaults.i18n] - Character count translations\n */\n\n/**\n * Character count translations\n *\n * @see {@link CharacterCount.defaults.i18n}\n * @typedef {object} CharacterCountTranslations\n *\n * Messages shown to users as they type. It provides feedback on how many words\n * or characters they have remaining or if they are over the limit. This also\n * includes a message used as an accessible description for the textarea.\n * @property {TranslationPluralForms} [charactersUnderLimit] - Message displayed\n * when the number of characters is under the configured maximum, `maxlength`.\n * This message is displayed visually and through assistive technologies. The\n * component will replace the `%{count}` placeholder with the number of\n * remaining characters. This is a [pluralised list of\n * messages](https://frontend.design-system.service.gov.uk/localise-govuk-frontend).\n * @property {string} [charactersAtLimit] - Message displayed when the number of\n * characters reaches the configured maximum, `maxlength`. This message is\n * displayed visually and through assistive technologies.\n * @property {TranslationPluralForms} [charactersOverLimit] - Message displayed\n * when the number of characters is over the configured maximum, `maxlength`.\n * This message is displayed visually and through assistive technologies. The\n * component will replace the `%{count}` placeholder with the number of\n * remaining characters. This is a [pluralised list of\n * messages](https://frontend.design-system.service.gov.uk/localise-govuk-frontend).\n * @property {TranslationPluralForms} [wordsUnderLimit] - Message displayed when\n * the number of words is under the configured maximum, `maxlength`. This\n * message is displayed visually and through assistive technologies. The\n * component will replace the `%{count}` placeholder with the number of\n * remaining words. This is a [pluralised list of\n * messages](https://frontend.design-system.service.gov.uk/localise-govuk-frontend).\n * @property {string} [wordsAtLimit] - Message displayed when the number of\n * words reaches the configured maximum, `maxlength`. This message is\n * displayed visually and through assistive technologies.\n * @property {TranslationPluralForms} [wordsOverLimit] - Message displayed when\n * the number of words is over the configured maximum, `maxlength`. This\n * message is displayed visually and through assistive technologies. The\n * component will replace the `%{count}` placeholder with the number of\n * remaining words. This is a [pluralised list of\n * messages](https://frontend.design-system.service.gov.uk/localise-govuk-frontend).\n * @property {TranslationPluralForms} [textareaDescription] - Message made\n * available to assistive technologies, if none is already present in the\n * HTML, to describe that the component accepts only a limited amount of\n * content. It is visible on the page when JavaScript is unavailable. The\n * component will replace the `%{count}` placeholder with the value of the\n * `maxlength` or `maxwords` parameter.\n */\n\n/**\n * @typedef {import('../../common/configuration.mjs').Schema} Schema\n * @typedef {import('../../i18n.mjs').TranslationPluralForms} TranslationPluralForms\n */\n"],"names":["CharacterCount","ConfigurableComponent","configOverride","datasetConfig","configOverrides","maxlength","undefined","maxwords","constructor","$root","config","_ref","_this$config$maxwords","$textarea","$visibleCountMessage","$screenReaderCountMessage","lastInputTimestamp","lastInputValue","valueChecker","i18n","maxLength","querySelector","HTMLTextAreaElement","HTMLInputElement","ElementError","component","element","expectedType","identifier","errors","validateConfig","schema","ConfigError","formatErrorMessage","I18n","locale","closestAttributeValue","Infinity","textareaDescriptionId","id","$textareaDescription","document","getElementById","textContent","match","t","count","insertAdjacentElement","createElement","className","setAttribute","classList","add","removeAttribute","bindChangeEvents","window","addEventListener","updateCountMessage","handleKeyUp","handleFocus","handleBlur","updateVisibleCountMessage","Date","now","setInterval","updateIfValueChanged","clearInterval","value","updateScreenReaderCountMessage","remainingNumber","isError","toggle","isOverThreshold","getCountMessage","text","_text$match","tokens","length","countType","formatCountMessage","translationKeySuffix","Math","abs","threshold","currentLength","thresholdValue","moduleName","defaults","Object","freeze","charactersUnderLimit","one","other","charactersAtLimit","charactersOverLimit","wordsUnderLimit","wordsAtLimit","wordsOverLimit","textareaDescription","properties","type","anyOf","required","errorMessage"],"mappings":";;;;;;AAUA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAMA,cAAc,SAASC,qBAAqB,CAAC;EA0CxD,CAACC,cAAc,CAAEC,CAAAA,aAAa,EAAE;IAC9B,IAAIC,eAAe,GAAG,EAAE,CAAA;AACxB,IAAA,IAAI,UAAU,IAAID,aAAa,IAAI,WAAW,IAAIA,aAAa,EAAE;AAC/DC,MAAAA,eAAe,GAAG;AAChBC,QAAAA,SAAS,EAAEC,SAAS;AACpBC,QAAAA,QAAQ,EAAED,SAAAA;OACX,CAAA;AACH,KAAA;AAEA,IAAA,OAAOF,eAAe,CAAA;AACxB,GAAA;;AAEA;AACF;AACA;AACA;AACEI,EAAAA,WAAWA,CAACC,KAAK,EAAEC,MAAM,GAAG,EAAE,EAAE;IAAA,IAAAC,IAAA,EAAAC,qBAAA,CAAA;AAC9B,IAAA,KAAK,CAACH,KAAK,EAAEC,MAAM,CAAC,CAAA;AAAA,IAAA,IAAA,CAzDtBG,SAAS,GAAA,KAAA,CAAA,CAAA;AAAA,IAAA,IAAA,CAGTC,oBAAoB,GAAA,KAAA,CAAA,CAAA;AAAA,IAAA,IAAA,CAGpBC,yBAAyB,GAAA,KAAA,CAAA,CAAA;IAAA,IAMzBC,CAAAA,kBAAkB,GAAG,IAAI,CAAA;IAAA,IAGzBC,CAAAA,cAAc,GAAG,EAAE,CAAA;IAAA,IAMnBC,CAAAA,YAAY,GAAG,IAAI,CAAA;AAAA,IAAA,IAAA,CAGnBC,IAAI,GAAA,KAAA,CAAA,CAAA;AAAA,IAAA,IAAA,CAGJC,SAAS,GAAA,KAAA,CAAA,CAAA;IAgCP,MAAMP,SAAS,GAAG,IAAI,CAACJ,KAAK,CAACY,aAAa,CAAC,2BAA2B,CAAC,CAAA;IACvE,IACE,EACER,SAAS,YAAYS,mBAAmB,IACxCT,SAAS,YAAYU,gBAAgB,CACtC,EACD;MACA,MAAM,IAAIC,YAAY,CAAC;AACrBC,QAAAA,SAAS,EAAEzB,cAAc;AACzB0B,QAAAA,OAAO,EAAEb,SAAS;AAClBc,QAAAA,YAAY,EAAE,yCAAyC;AACvDC,QAAAA,UAAU,EAAE,0CAAA;AACd,OAAC,CAAC,CAAA;AACJ,KAAA;IAGA,MAAMC,MAAM,GAAGC,cAAc,CAAC9B,cAAc,CAAC+B,MAAM,EAAE,IAAI,CAACrB,MAAM,CAAC,CAAA;AACjE,IAAA,IAAImB,MAAM,CAAC,CAAC,CAAC,EAAE;AACb,MAAA,MAAM,IAAIG,WAAW,CAACC,kBAAkB,CAACjC,cAAc,EAAE6B,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;AACtE,KAAA;IAEA,IAAI,CAACV,IAAI,GAAG,IAAIe,IAAI,CAAC,IAAI,CAACxB,MAAM,CAACS,IAAI,EAAE;AAErCgB,MAAAA,MAAM,EAAEC,qBAAqB,CAAC,IAAI,CAAC3B,KAAK,EAAE,MAAM,CAAA;AAClD,KAAC,CAAC,CAAA;IAGF,IAAI,CAACW,SAAS,GAAAT,CAAAA,IAAA,IAAAC,qBAAA,GAAG,IAAI,CAACF,MAAM,CAACH,QAAQ,KAAAK,IAAAA,GAAAA,qBAAA,GAAI,IAAI,CAACF,MAAM,CAACL,SAAS,KAAA,IAAA,GAAAM,IAAA,GAAI0B,QAAQ,CAAA;IAE1E,IAAI,CAACxB,SAAS,GAAGA,SAAS,CAAA;IAE1B,MAAMyB,qBAAqB,GAAG,CAAG,EAAA,IAAI,CAACzB,SAAS,CAAC0B,EAAE,CAAO,KAAA,CAAA,CAAA;AACzD,IAAA,MAAMC,oBAAoB,GAAGC,QAAQ,CAACC,cAAc,CAACJ,qBAAqB,CAAC,CAAA;IAC3E,IAAI,CAACE,oBAAoB,EAAE;MACzB,MAAM,IAAIhB,YAAY,CAAC;AACrBC,QAAAA,SAAS,EAAEzB,cAAc;AACzB0B,QAAAA,OAAO,EAAEc,oBAAoB;QAC7BZ,UAAU,EAAE,wBAAwBU,qBAAqB,CAAA,IAAA,CAAA;AAC3D,OAAC,CAAC,CAAA;AACJ,KAAA;IAKA,IAAI,CAAA,EAAGE,oBAAoB,CAACG,WAAW,CAAA,CAAE,CAACC,KAAK,CAAC,OAAO,CAAC,EAAE;MACxDJ,oBAAoB,CAACG,WAAW,GAAG,IAAI,CAACxB,IAAI,CAAC0B,CAAC,CAAC,qBAAqB,EAAE;QACpEC,KAAK,EAAE,IAAI,CAAC1B,SAAAA;AACd,OAAC,CAAC,CAAA;AACJ,KAAA;IAIA,IAAI,CAACP,SAAS,CAACkC,qBAAqB,CAAC,UAAU,EAAEP,oBAAoB,CAAC,CAAA;AAItE,IAAA,MAAMzB,yBAAyB,GAAG0B,QAAQ,CAACO,aAAa,CAAC,KAAK,CAAC,CAAA;IAC/DjC,yBAAyB,CAACkC,SAAS,GACjC,wDAAwD,CAAA;AAC1DlC,IAAAA,yBAAyB,CAACmC,YAAY,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAA;IAC7D,IAAI,CAACnC,yBAAyB,GAAGA,yBAAyB,CAAA;AAC1DyB,IAAAA,oBAAoB,CAACO,qBAAqB,CACxC,UAAU,EACVhC,yBACF,CAAC,CAAA;AAKD,IAAA,MAAMD,oBAAoB,GAAG2B,QAAQ,CAACO,aAAa,CAAC,KAAK,CAAC,CAAA;AAC1DlC,IAAAA,oBAAoB,CAACmC,SAAS,GAAGT,oBAAoB,CAACS,SAAS,CAAA;AAC/DnC,IAAAA,oBAAoB,CAACqC,SAAS,CAACC,GAAG,CAAC,+BAA+B,CAAC,CAAA;AACnEtC,IAAAA,oBAAoB,CAACoC,YAAY,CAAC,aAAa,EAAE,MAAM,CAAC,CAAA;IACxD,IAAI,CAACpC,oBAAoB,GAAGA,oBAAoB,CAAA;AAChD0B,IAAAA,oBAAoB,CAACO,qBAAqB,CAAC,UAAU,EAAEjC,oBAAoB,CAAC,CAAA;AAG5E0B,IAAAA,oBAAoB,CAACW,SAAS,CAACC,GAAG,CAAC,uBAAuB,CAAC,CAAA;AAG3D,IAAA,IAAI,CAACvC,SAAS,CAACwC,eAAe,CAAC,WAAW,CAAC,CAAA;IAE3C,IAAI,CAACC,gBAAgB,EAAE,CAAA;IAKvBC,MAAM,CAACC,gBAAgB,CAAC,UAAU,EAAE,MAAM,IAAI,CAACC,kBAAkB,EAAE,CAAC,CAAA;IAKpE,IAAI,CAACA,kBAAkB,EAAE,CAAA;AAC3B,GAAA;AAUAH,EAAAA,gBAAgBA,GAAG;AACjB,IAAA,IAAI,CAACzC,SAAS,CAAC2C,gBAAgB,CAAC,OAAO,EAAE,MAAM,IAAI,CAACE,WAAW,EAAE,CAAC,CAAA;AAGlE,IAAA,IAAI,CAAC7C,SAAS,CAAC2C,gBAAgB,CAAC,OAAO,EAAE,MAAM,IAAI,CAACG,WAAW,EAAE,CAAC,CAAA;AAClE,IAAA,IAAI,CAAC9C,SAAS,CAAC2C,gBAAgB,CAAC,MAAM,EAAE,MAAM,IAAI,CAACI,UAAU,EAAE,CAAC,CAAA;AAClE,GAAA;AAUAF,EAAAA,WAAWA,GAAG;IACZ,IAAI,CAACG,yBAAyB,EAAE,CAAA;AAChC,IAAA,IAAI,CAAC7C,kBAAkB,GAAG8C,IAAI,CAACC,GAAG,EAAE,CAAA;AACtC,GAAA;AAiBAJ,EAAAA,WAAWA,GAAG;AACZ,IAAA,IAAI,CAACzC,YAAY,GAAGqC,MAAM,CAACS,WAAW,CAAC,MAAM;AAC3C,MAAA,IACE,CAAC,IAAI,CAAChD,kBAAkB,IACxB8C,IAAI,CAACC,GAAG,EAAE,GAAG,GAAG,IAAI,IAAI,CAAC/C,kBAAkB,EAC3C;QACA,IAAI,CAACiD,oBAAoB,EAAE,CAAA;AAC7B,OAAA;KACD,EAAE,IAAI,CAAC,CAAA;AACV,GAAA;AASAL,EAAAA,UAAUA,GAAG;IAEX,IAAI,IAAI,CAAC1C,YAAY,EAAE;AACrBqC,MAAAA,MAAM,CAACW,aAAa,CAAC,IAAI,CAAChD,YAAY,CAAC,CAAA;AACzC,KAAA;AACF,GAAA;AAOA+C,EAAAA,oBAAoBA,GAAG;IACrB,IAAI,IAAI,CAACpD,SAAS,CAACsD,KAAK,KAAK,IAAI,CAAClD,cAAc,EAAE;AAChD,MAAA,IAAI,CAACA,cAAc,GAAG,IAAI,CAACJ,SAAS,CAACsD,KAAK,CAAA;MAC1C,IAAI,CAACV,kBAAkB,EAAE,CAAA;AAC3B,KAAA;AACF,GAAA;AAUAA,EAAAA,kBAAkBA,GAAG;IACnB,IAAI,CAACI,yBAAyB,EAAE,CAAA;IAChC,IAAI,CAACO,8BAA8B,EAAE,CAAA;AACvC,GAAA;AAOAP,EAAAA,yBAAyBA,GAAG;AAC1B,IAAA,MAAMQ,eAAe,GAAG,IAAI,CAACjD,SAAS,GAAG,IAAI,CAAC0B,KAAK,CAAC,IAAI,CAACjC,SAAS,CAACsD,KAAK,CAAC,CAAA;AACzE,IAAA,MAAMG,OAAO,GAAGD,eAAe,GAAG,CAAC,CAAA;AAInC,IAAA,IAAI,CAACvD,oBAAoB,CAACqC,SAAS,CAACoB,MAAM,CACxC,0CAA0C,EAC1C,CAAC,IAAI,CAACC,eAAe,EACvB,CAAC,CAAA;IAGD,IAAI,CAAC3D,SAAS,CAACsC,SAAS,CAACoB,MAAM,CAAC,uBAAuB,EAAED,OAAO,CAAC,CAAA;IACjE,IAAI,CAACxD,oBAAoB,CAACqC,SAAS,CAACoB,MAAM,CAAC,qBAAqB,EAAED,OAAO,CAAC,CAAA;IAC1E,IAAI,CAACxD,oBAAoB,CAACqC,SAAS,CAACoB,MAAM,CAAC,YAAY,EAAE,CAACD,OAAO,CAAC,CAAA;IAGlE,IAAI,CAACxD,oBAAoB,CAAC6B,WAAW,GAAG,IAAI,CAAC8B,eAAe,EAAE,CAAA;AAChE,GAAA;AAOAL,EAAAA,8BAA8BA,GAAG;AAG/B,IAAA,IAAI,IAAI,CAACI,eAAe,EAAE,EAAE;AAC1B,MAAA,IAAI,CAACzD,yBAAyB,CAACsC,eAAe,CAAC,aAAa,CAAC,CAAA;AAC/D,KAAC,MAAM;MACL,IAAI,CAACtC,yBAAyB,CAACmC,YAAY,CAAC,aAAa,EAAE,MAAM,CAAC,CAAA;AACpE,KAAA;IAGA,IAAI,CAACnC,yBAAyB,CAAC4B,WAAW,GAAG,IAAI,CAAC8B,eAAe,EAAE,CAAA;AACrE,GAAA;EAUA3B,KAAKA,CAAC4B,IAAI,EAAE;AACV,IAAA,IAAI,IAAI,CAAChE,MAAM,CAACH,QAAQ,EAAE;AAAA,MAAA,IAAAoE,WAAA,CAAA;AACxB,MAAA,MAAMC,MAAM,GAAA,CAAAD,WAAA,GAAGD,IAAI,CAAC9B,KAAK,CAAC,MAAM,CAAC,KAAA+B,IAAAA,GAAAA,WAAA,GAAI,EAAE,CAAA;MACvC,OAAOC,MAAM,CAACC,MAAM,CAAA;AACtB,KAAA;IAEA,OAAOH,IAAI,CAACG,MAAM,CAAA;AACpB,GAAA;AAQAJ,EAAAA,eAAeA,GAAG;AAChB,IAAA,MAAMJ,eAAe,GAAG,IAAI,CAACjD,SAAS,GAAG,IAAI,CAAC0B,KAAK,CAAC,IAAI,CAACjC,SAAS,CAACsD,KAAK,CAAC,CAAA;IACzE,MAAMW,SAAS,GAAG,IAAI,CAACpE,MAAM,CAACH,QAAQ,GAAG,OAAO,GAAG,YAAY,CAAA;AAC/D,IAAA,OAAO,IAAI,CAACwE,kBAAkB,CAACV,eAAe,EAAES,SAAS,CAAC,CAAA;AAC5D,GAAA;AAWAC,EAAAA,kBAAkBA,CAACV,eAAe,EAAES,SAAS,EAAE;IAC7C,IAAIT,eAAe,KAAK,CAAC,EAAE;MACzB,OAAO,IAAI,CAAClD,IAAI,CAAC0B,CAAC,CAAC,CAAA,EAAGiC,SAAS,CAAA,OAAA,CAAS,CAAC,CAAA;AAC3C,KAAA;IAEA,MAAME,oBAAoB,GACxBX,eAAe,GAAG,CAAC,GAAG,WAAW,GAAG,YAAY,CAAA;IAElD,OAAO,IAAI,CAAClD,IAAI,CAAC0B,CAAC,CAAC,CAAA,EAAGiC,SAAS,CAAA,EAAGE,oBAAoB,CAAA,CAAE,EAAE;AACxDlC,MAAAA,KAAK,EAAEmC,IAAI,CAACC,GAAG,CAACb,eAAe,CAAA;AACjC,KAAC,CAAC,CAAA;AACJ,GAAA;AAaAG,EAAAA,eAAeA,GAAG;AAEhB,IAAA,IAAI,CAAC,IAAI,CAAC9D,MAAM,CAACyE,SAAS,EAAE;AAC1B,MAAA,OAAO,IAAI,CAAA;AACb,KAAA;IAGA,MAAMC,aAAa,GAAG,IAAI,CAACtC,KAAK,CAAC,IAAI,CAACjC,SAAS,CAACsD,KAAK,CAAC,CAAA;AACtD,IAAA,MAAM/C,SAAS,GAAG,IAAI,CAACA,SAAS,CAAA;IAEhC,MAAMiE,cAAc,GAAIjE,SAAS,GAAG,IAAI,CAACV,MAAM,CAACyE,SAAS,GAAI,GAAG,CAAA;IAEhE,OAAOE,cAAc,IAAID,aAAa,CAAA;AACxC,GAAA;AAmEF,CAAA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AAtfapF,cAAc,CAqXlBsF,UAAU,GAAG,uBAAuB,CAAA;AArXhCtF,cAAc,CA8XlBuF,QAAQ,GAAGC,MAAM,CAACC,MAAM,CAAC;AAC9BN,EAAAA,SAAS,EAAE,CAAC;AACZhE,EAAAA,IAAI,EAAE;AAEJuE,IAAAA,oBAAoB,EAAE;AACpBC,MAAAA,GAAG,EAAE,uCAAuC;AAC5CC,MAAAA,KAAK,EAAE,wCAAA;KACR;AACDC,IAAAA,iBAAiB,EAAE,iCAAiC;AACpDC,IAAAA,mBAAmB,EAAE;AACnBH,MAAAA,GAAG,EAAE,sCAAsC;AAC3CC,MAAAA,KAAK,EAAE,uCAAA;KACR;AAEDG,IAAAA,eAAe,EAAE;AACfJ,MAAAA,GAAG,EAAE,kCAAkC;AACvCC,MAAAA,KAAK,EAAE,mCAAA;KACR;AACDI,IAAAA,YAAY,EAAE,4BAA4B;AAC1CC,IAAAA,cAAc,EAAE;AACdN,MAAAA,GAAG,EAAE,iCAAiC;AACtCC,MAAAA,KAAK,EAAE,kCAAA;KACR;AACDM,IAAAA,mBAAmB,EAAE;AACnBN,MAAAA,KAAK,EAAE,EAAA;AACT,KAAA;AACF,GAAA;AACF,CAAC,CAAC,CAAA;AAzZS5F,cAAc,CAialB+B,MAAM,GAAGyD,MAAM,CAACC,MAAM,CAAC;AAC5BU,EAAAA,UAAU,EAAE;AACVhF,IAAAA,IAAI,EAAE;AAAEiF,MAAAA,IAAI,EAAE,QAAA;KAAU;AACxB7F,IAAAA,QAAQ,EAAE;AAAE6F,MAAAA,IAAI,EAAE,QAAA;KAAU;AAC5B/F,IAAAA,SAAS,EAAE;AAAE+F,MAAAA,IAAI,EAAE,QAAA;KAAU;AAC7BjB,IAAAA,SAAS,EAAE;AAAEiB,MAAAA,IAAI,EAAE,QAAA;AAAS,KAAA;GAC7B;AACDC,EAAAA,KAAK,EAAE,CACL;IACEC,QAAQ,EAAE,CAAC,UAAU,CAAC;AACtBC,IAAAA,YAAY,EAAE,mDAAA;AAChB,GAAC,EACD;IACED,QAAQ,EAAE,CAAC,WAAW,CAAC;AACvBC,IAAAA,YAAY,EAAE,mDAAA;GACf,CAAA;AAEL,CAAC,CAAC;;;;"}
@@ -164,7 +164,7 @@
164
164
  "name": "charactersUnderLimitText",
165
165
  "type": "object",
166
166
  "required": false,
167
- "description": "Message displayed when the number of characters is under the configured maximum, `maxlength`. This message is displayed visually and through assistive technologies. The component will replace the `%{count}` placeholder with the number of remaining characters. This is a [pluralised list of messages](https://frontend.design-system.service.gov.uk/localise-govuk-frontend)."
167
+ "description": "Message displayed when the number of characters is under the configured maximum, `maxlength`. This message is displayed visually and through assistive technologies. The component will replace the `%{count}` placeholder with the number of remaining characters. [Our pluralisation rules apply to this macro option](https://frontend.design-system.service.gov.uk/localise-govuk-frontend/#understanding-pluralisation-rules)."
168
168
  },
169
169
  {
170
170
  "name": "charactersAtLimitText",
@@ -176,13 +176,13 @@
176
176
  "name": "charactersOverLimitText",
177
177
  "type": "object",
178
178
  "required": false,
179
- "description": "Message displayed when the number of characters is over the configured maximum, `maxlength`. This message is displayed visually and through assistive technologies. The component will replace the `%{count}` placeholder with the number of characters above the maximum. This is a [pluralised list of messages](https://frontend.design-system.service.gov.uk/localise-govuk-frontend)."
179
+ "description": "Message displayed when the number of characters is over the configured maximum, `maxlength`. This message is displayed visually and through assistive technologies. The component will replace the `%{count}` placeholder with the number of characters above the maximum.[Our pluralisation rules apply to this macro option](https://frontend.design-system.service.gov.uk/localise-govuk-frontend/#understanding-pluralisation-rules)."
180
180
  },
181
181
  {
182
182
  "name": "wordsUnderLimitText",
183
183
  "type": "object",
184
184
  "required": false,
185
- "description": "Message displayed when the number of words is under the configured maximum, `maxwords`. This message is displayed visually and through assistive technologies. The component will replace the `%{count}` placeholder with the number of remaining words. This is a [pluralised list of messages](https://frontend.design-system.service.gov.uk/localise-govuk-frontend)."
185
+ "description": "Message displayed when the number of words is under the configured maximum, `maxwords`. This message is displayed visually and through assistive technologies. The component will replace the `%{count}` placeholder with the number of remaining words. [Our pluralisation rules apply to this macro option](https://frontend.design-system.service.gov.uk/localise-govuk-frontend/#understanding-pluralisation-rules)."
186
186
  },
187
187
  {
188
188
  "name": "wordsAtLimitText",
@@ -194,6 +194,6 @@
194
194
  "name": "wordsOverLimitText",
195
195
  "type": "object",
196
196
  "required": false,
197
- "description": "Message displayed when the number of words is over the configured maximum, `maxwords`. This message is displayed visually and through assistive technologies. The component will replace the `%{count}` placeholder with the number of characters above the maximum. This is a [pluralised list of messages](https://frontend.design-system.service.gov.uk/localise-govuk-frontend)."
197
+ "description": "Message displayed when the number of words is over the configured maximum, `maxwords`. This message is displayed visually and through assistive technologies. The component will replace the `%{count}` placeholder with the number of characters above the maximum. [Our pluralisation rules apply to this macro option](https://frontend.design-system.service.gov.uk/localise-govuk-frontend/#understanding-pluralisation-rules)."
198
198
  }
199
199
  ]
@@ -1,7 +1,7 @@
1
1
  (function (global, factory) {
2
2
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3
3
  typeof define === 'function' && define.amd ? define(['exports'], factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.GOVUKFrontend = {}));
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.GOVUKFrontend = global.GOVUKFrontend || {}));
5
5
  })(this, (function (exports) { 'use strict';
6
6
 
7
7
  function isInitialised($root, moduleName) {
@@ -26,29 +26,6 @@
26
26
  function formatErrorMessage(Component, message) {
27
27
  return `${Component.moduleName}: ${message}`;
28
28
  }
29
-
30
- /**
31
- * Schema for component config
32
- *
33
- * @typedef {object} Schema
34
- * @property {{ [field: string]: SchemaProperty | undefined }} properties - Schema properties
35
- * @property {SchemaCondition[]} [anyOf] - List of schema conditions
36
- */
37
-
38
- /**
39
- * Schema property for component config
40
- *
41
- * @typedef {object} SchemaProperty
42
- * @property {'string' | 'boolean' | 'number' | 'object'} type - Property type
43
- */
44
-
45
- /**
46
- * Schema condition for component config
47
- *
48
- * @typedef {object} SchemaCondition
49
- * @property {string[]} required - List of required config fields
50
- * @property {string} errorMessage - Error message when required config fields not provided
51
- */
52
29
  /**
53
30
  * @typedef ComponentWithModuleName
54
31
  * @property {string} moduleName - Name of the component
@@ -1 +1 @@
1
- {"version":3,"file":"checkboxes.bundle.js","sources":["../../../../src/govuk/common/index.mjs","../../../../src/govuk/errors/index.mjs","../../../../src/govuk/govuk-frontend-component.mjs","../../../../src/govuk/components/checkboxes/checkboxes.mjs"],"sourcesContent":["import { normaliseString } from './normalise-string.mjs'\n\n/**\n * Common helpers which do not require polyfill.\n *\n * IMPORTANT: If a helper require a polyfill, please isolate it in its own module\n * so that the polyfill can be properly tree-shaken and does not burden\n * the components that do not need that helper\n */\n\n/**\n * Config merging function\n *\n * Takes any number of objects and combines them together, with\n * greatest priority on the LAST item passed in.\n *\n * @internal\n * @param {...{ [key: string]: unknown }} configObjects - Config objects to merge\n * @returns {{ [key: string]: unknown }} A merged config object\n */\nexport function mergeConfigs(...configObjects) {\n // Start with an empty object as our base\n /** @type {{ [key: string]: unknown }} */\n const formattedConfigObject = {}\n\n // Loop through each of the passed objects\n for (const configObject of configObjects) {\n for (const key of Object.keys(configObject)) {\n const option = formattedConfigObject[key]\n const override = configObject[key]\n\n // Push their keys one-by-one into formattedConfigObject. Any duplicate\n // keys with object values will be merged, otherwise the new value will\n // override the existing value.\n if (isObject(option) && isObject(override)) {\n // @ts-expect-error Index signature for type 'string' is missing\n formattedConfigObject[key] = mergeConfigs(option, override)\n } else {\n // Apply override\n formattedConfigObject[key] = override\n }\n }\n }\n\n return formattedConfigObject\n}\n\n/**\n * Extracts keys starting with a particular namespace from dataset ('data-*')\n * object, removing the namespace in the process, normalising all values\n *\n * @internal\n * @param {{ schema: Schema }} Component - Component class\n * @param {DOMStringMap} dataset - The object to extract key-value pairs from\n * @param {string} namespace - The namespace to filter keys with\n * @returns {ObjectNested | undefined} Nested object with dot-separated key namespace removed\n */\nexport function extractConfigByNamespace(Component, dataset, namespace) {\n const property = Component.schema.properties[namespace]\n\n // Only extract configs for object schema properties\n if (property?.type !== 'object') {\n return\n }\n\n // Add default empty config\n const newObject = {\n [namespace]: /** @type {ObjectNested} */ ({})\n }\n\n for (const [key, value] of Object.entries(dataset)) {\n /** @type {ObjectNested | ObjectNested[NestedKey]} */\n let current = newObject\n\n // Split the key into parts, using . as our namespace separator\n const keyParts = key.split('.')\n\n /**\n * Create new level per part\n *\n * e.g. 'i18n.textareaDescription.other' becomes\n * `{ i18n: { textareaDescription: { other } } }`\n */\n for (const [index, name] of keyParts.entries()) {\n if (typeof current === 'object') {\n // Drop down to nested object until the last part\n if (index < keyParts.length - 1) {\n // New nested object (optionally) replaces existing value\n if (!isObject(current[name])) {\n current[name] = {}\n }\n\n // Drop down into new or existing nested object\n current = current[name]\n } else if (key !== namespace) {\n // Normalised value (optionally) replaces existing value\n current[name] = normaliseString(value)\n }\n }\n }\n }\n\n return newObject[namespace]\n}\n\n/**\n * Get hash fragment from URL\n *\n * Extract the hash fragment (everything after the hash) from a URL,\n * but not including the hash symbol\n *\n * @private\n * @param {string} url - URL\n * @returns {string | undefined} Fragment from URL, without the hash\n */\nexport function getFragmentFromUrl(url) {\n if (!url.includes('#')) {\n return undefined\n }\n\n return url.split('#').pop()\n}\n\n/**\n * Get GOV.UK Frontend breakpoint value from CSS custom property\n *\n * @private\n * @param {string} name - Breakpoint name\n * @returns {{ property: string, value?: string }} Breakpoint object\n */\nexport function getBreakpoint(name) {\n const property = `--govuk-frontend-breakpoint-${name}`\n\n // Get value from `<html>` with breakpoints on CSS :root\n const value = window\n .getComputedStyle(document.documentElement)\n .getPropertyValue(property)\n\n return {\n property,\n value: value || undefined\n }\n}\n\n/**\n * Move focus to element\n *\n * Sets tabindex to -1 to make the element programmatically focusable,\n * but removes it on blur as the element doesn't need to be focused again.\n *\n * @private\n * @template {HTMLElement} FocusElement\n * @param {FocusElement} $element - HTML element\n * @param {object} [options] - Handler options\n * @param {function(this: FocusElement): void} [options.onBeforeFocus] - Callback before focus\n * @param {function(this: FocusElement): void} [options.onBlur] - Callback on blur\n */\nexport function setFocus($element, options = {}) {\n const isFocusable = $element.getAttribute('tabindex')\n\n if (!isFocusable) {\n $element.setAttribute('tabindex', '-1')\n }\n\n /**\n * Handle element focus\n */\n function onFocus() {\n $element.addEventListener('blur', onBlur, { once: true })\n }\n\n /**\n * Handle element blur\n */\n function onBlur() {\n options.onBlur?.call($element)\n\n if (!isFocusable) {\n $element.removeAttribute('tabindex')\n }\n }\n\n // Add listener to reset element on blur, after focus\n $element.addEventListener('focus', onFocus, { once: true })\n\n // Focus element\n options.onBeforeFocus?.call($element)\n $element.focus()\n}\n\n/**\n * Checks if component is already initialised\n *\n * @internal\n * @param {Element} $root - HTML element to be checked\n * @param {string} moduleName - name of component module\n * @returns {boolean} Whether component is already initialised\n */\nexport function isInitialised($root, moduleName) {\n return (\n $root instanceof HTMLElement &&\n $root.hasAttribute(`data-${moduleName}-init`)\n )\n}\n\n/**\n * Checks if GOV.UK Frontend is supported on this page\n *\n * Some browsers will load and run our JavaScript but GOV.UK Frontend\n * won't be supported.\n *\n * @param {HTMLElement | null} [$scope] - (internal) `<body>` HTML element checked for browser support\n * @returns {boolean} Whether GOV.UK Frontend is supported on this page\n */\nexport function isSupported($scope = document.body) {\n if (!$scope) {\n return false\n }\n\n return $scope.classList.contains('govuk-frontend-supported')\n}\n\n/**\n * Validate component config by schema\n *\n * Follows limited examples in JSON schema for wider support in future\n *\n * {@link https://ajv.js.org/json-schema.html#compound-keywords}\n * {@link https://ajv.js.org/packages/ajv-errors.html#single-message}\n *\n * @internal\n * @param {Schema} schema - Config schema\n * @param {{ [key: string]: unknown }} config - Component config\n * @returns {string[]} List of validation errors\n */\nexport function validateConfig(schema, config) {\n const validationErrors = []\n\n // Check errors for each schema\n for (const [name, conditions] of Object.entries(schema)) {\n const errors = []\n\n // Check errors for each schema condition\n if (Array.isArray(conditions)) {\n for (const { required, errorMessage } of conditions) {\n if (!required.every((key) => !!config[key])) {\n errors.push(errorMessage) // Missing config key value\n }\n }\n\n // Check one condition passes or add errors\n if (name === 'anyOf' && !(conditions.length - errors.length >= 1)) {\n validationErrors.push(...errors)\n }\n }\n }\n\n return validationErrors\n}\n\n/**\n * Check for an array\n *\n * @internal\n * @param {unknown} option - Option to check\n * @returns {boolean} Whether the option is an array\n */\nfunction isArray(option) {\n return Array.isArray(option)\n}\n\n/**\n * Check for an object\n *\n * @internal\n * @param {unknown} option - Option to check\n * @returns {boolean} Whether the option is an object\n */\nfunction isObject(option) {\n return !!option && typeof option === 'object' && !isArray(option)\n}\n\n/**\n * Format error message\n *\n * @internal\n * @param {ComponentWithModuleName} Component - Component that threw the error\n * @param {string} message - Error message\n * @returns {string} - Formatted error message\n */\nexport function formatErrorMessage(Component, message) {\n return `${Component.moduleName}: ${message}`\n}\n\n/**\n * Schema for component config\n *\n * @typedef {object} Schema\n * @property {{ [field: string]: SchemaProperty | undefined }} properties - Schema properties\n * @property {SchemaCondition[]} [anyOf] - List of schema conditions\n */\n\n/**\n * Schema property for component config\n *\n * @typedef {object} SchemaProperty\n * @property {'string' | 'boolean' | 'number' | 'object'} type - Property type\n */\n\n/**\n * Schema condition for component config\n *\n * @typedef {object} SchemaCondition\n * @property {string[]} required - List of required config fields\n * @property {string} errorMessage - Error message when required config fields not provided\n */\n\n/**\n * @internal\n * @typedef {keyof ObjectNested} NestedKey\n * @typedef {{ [key: string]: string | boolean | number | ObjectNested | undefined }} ObjectNested\n */\n\n/* eslint-disable jsdoc/valid-types --\n * `{new(...args: any[] ): object}` is not recognised as valid\n * https://github.com/gajus/eslint-plugin-jsdoc/issues/145#issuecomment-1308722878\n * https://github.com/jsdoc-type-pratt-parser/jsdoc-type-pratt-parser/issues/131\n **/\n\n/**\n * @typedef ComponentWithModuleName\n * @property {string} moduleName - Name of the component\n */\n\n/* eslint-enable jsdoc/valid-types */\n","import { formatErrorMessage } from '../common/index.mjs'\n\n/**\n * GOV.UK Frontend error\n *\n * A base class for `Error`s thrown by GOV.UK Frontend.\n *\n * It is meant to be extended into specific types of errors\n * to be thrown by our code.\n *\n * @example\n * ```js\n * class MissingRootError extends GOVUKFrontendError {\n * // Setting an explicit name is important as extending the class will not\n * // set a new `name` on the subclass. The `name` property is important\n * // to ensure intelligible error names even if the class name gets\n * // mangled by a minifier\n * name = \"MissingRootError\"\n * }\n * ```\n * @virtual\n */\nexport class GOVUKFrontendError extends Error {\n name = 'GOVUKFrontendError'\n}\n\n/**\n * Indicates that GOV.UK Frontend is not supported\n */\nexport class SupportError extends GOVUKFrontendError {\n name = 'SupportError'\n\n /**\n * Checks if GOV.UK Frontend is supported on this page\n *\n * @param {HTMLElement | null} [$scope] - HTML element `<body>` checked for browser support\n */\n constructor($scope = document.body) {\n const supportMessage =\n 'noModule' in HTMLScriptElement.prototype\n ? 'GOV.UK Frontend initialised without `<body class=\"govuk-frontend-supported\">` from template `<script>` snippet'\n : 'GOV.UK Frontend is not supported in this browser'\n\n super(\n $scope\n ? supportMessage\n : 'GOV.UK Frontend initialised without `<script type=\"module\">`'\n )\n }\n}\n\n/**\n * Indicates that a component has received an illegal configuration\n */\nexport class ConfigError extends GOVUKFrontendError {\n name = 'ConfigError'\n}\n\n/**\n * Indicates an issue with an element (possibly `null` or `undefined`)\n */\nexport class ElementError extends GOVUKFrontendError {\n name = 'ElementError'\n\n /**\n * @internal\n * @overload\n * @param {string} message - Element error message\n */\n\n /**\n * @internal\n * @overload\n * @param {ElementErrorOptions} options - Element error options\n */\n\n /**\n * @internal\n * @param {string | ElementErrorOptions} messageOrOptions - Element error message or options\n */\n constructor(messageOrOptions) {\n let message = typeof messageOrOptions === 'string' ? messageOrOptions : ''\n\n // Build message from options\n if (typeof messageOrOptions === 'object') {\n const { component, identifier, element, expectedType } = messageOrOptions\n\n message = identifier\n\n // Append reason\n message += element\n ? ` is not of type ${expectedType ?? 'HTMLElement'}`\n : ' not found'\n\n message = formatErrorMessage(component, message)\n }\n\n super(message)\n }\n}\n\n/**\n * Indicates that a component is already initialised\n */\nexport class InitError extends GOVUKFrontendError {\n name = 'InitError'\n\n /**\n * @internal\n * @param {ComponentWithModuleName | string} componentOrMessage - name of the component module\n */\n constructor(componentOrMessage) {\n const message =\n typeof componentOrMessage === 'string'\n ? componentOrMessage\n : formatErrorMessage(\n componentOrMessage,\n `Root element (\\`$root\\`) already initialised`\n )\n\n super(message)\n }\n}\n\n/**\n * Element error options\n *\n * @internal\n * @typedef {object} ElementErrorOptions\n * @property {string} identifier - An identifier that'll let the user understand which element has an error. This is whatever makes the most sense\n * @property {Element | null} [element] - The element in error\n * @property {string} [expectedType] - The type that was expected for the identifier\n * @property {ComponentWithModuleName} component - Component throwing the error\n */\n\n/**\n * @typedef {import('../common/index.mjs').ComponentWithModuleName} ComponentWithModuleName\n */\n","import { isInitialised, isSupported } from './common/index.mjs'\nimport { ElementError, InitError, SupportError } from './errors/index.mjs'\n\n/**\n * Base Component class\n *\n * Centralises the behaviours shared by our components\n *\n * @virtual\n * @template {Element} [RootElementType=HTMLElement]\n */\nexport class GOVUKFrontendComponent {\n /**\n * @type {typeof Element}\n */\n static elementType = HTMLElement\n\n // allows Typescript user to work around the lack of types\n // in GOVUKFrontend package, Typescript is not aware of $root\n // in components that extend GOVUKFrontendComponent\n /**\n * Returns the root element of the component\n *\n * @protected\n * @returns {RootElementType} - the root element of component\n */\n get $root() {\n return this._$root\n }\n\n /**\n * @protected\n * @type {RootElementType}\n */\n _$root\n\n /**\n * Constructs a new component, validating that GOV.UK Frontend is supported\n *\n * @internal\n * @param {Element | null} [$root] - HTML element to use for component\n */\n constructor($root) {\n const childConstructor = /** @type {ChildClassConstructor} */ (\n this.constructor\n )\n\n // TypeScript does not enforce that inheriting classes will define a `moduleName`\n // (even if we add a `@virtual` `static moduleName` property to this class).\n // While we trust users to do this correctly, we do a little check to provide them\n // a helpful error message.\n //\n // After this, we'll be sure that `childConstructor` has a `moduleName`\n // as expected of the `ChildClassConstructor` we've cast `this.constructor` to.\n if (typeof childConstructor.moduleName !== 'string') {\n throw new InitError(`\\`moduleName\\` not defined in component`)\n }\n\n if (!($root instanceof childConstructor.elementType)) {\n throw new ElementError({\n element: $root,\n component: childConstructor,\n identifier: 'Root element (`$root`)',\n expectedType: childConstructor.elementType.name\n })\n } else {\n this._$root = /** @type {RootElementType} */ ($root)\n }\n\n childConstructor.checkSupport()\n\n this.checkInitialised()\n\n const moduleName = childConstructor.moduleName\n\n this.$root.setAttribute(`data-${moduleName}-init`, '')\n }\n\n /**\n * Validates whether component is already initialised\n *\n * @private\n * @throws {InitError} when component is already initialised\n */\n checkInitialised() {\n const constructor = /** @type {ChildClassConstructor} */ (this.constructor)\n const moduleName = constructor.moduleName\n\n if (moduleName && isInitialised(this.$root, moduleName)) {\n throw new InitError(constructor)\n }\n }\n\n /**\n * Validates whether components are supported\n *\n * @throws {SupportError} when the components are not supported\n */\n static checkSupport() {\n if (!isSupported()) {\n throw new SupportError()\n }\n }\n}\n\n/**\n * @typedef ChildClass\n * @property {string} moduleName - The module name that'll be looked for in the DOM when initialising the component\n */\n\n/**\n * @typedef {typeof GOVUKFrontendComponent & ChildClass} ChildClassConstructor\n */\n","import { ElementError } from '../../errors/index.mjs'\nimport { GOVUKFrontendComponent } from '../../govuk-frontend-component.mjs'\n\n/**\n * Checkboxes component\n *\n * @preserve\n */\nexport class Checkboxes extends GOVUKFrontendComponent {\n /** @private */\n $inputs\n\n /**\n * Checkboxes can be associated with a 'conditionally revealed' content block\n * – for example, a checkbox for 'Phone' could reveal an additional form field\n * for the user to enter their phone number.\n *\n * These associations are made using a `data-aria-controls` attribute, which\n * is promoted to an aria-controls attribute during initialisation.\n *\n * We also need to restore the state of any conditional reveals on the page\n * (for example if the user has navigated back), and set up event handlers to\n * keep the reveal in sync with the checkbox state.\n *\n * @param {Element | null} $root - HTML element to use for checkboxes\n */\n constructor($root) {\n super($root)\n\n const $inputs = this.$root.querySelectorAll('input[type=\"checkbox\"]')\n if (!$inputs.length) {\n throw new ElementError({\n component: Checkboxes,\n identifier: 'Form inputs (`<input type=\"checkbox\">`)'\n })\n }\n\n this.$inputs = $inputs\n\n this.$inputs.forEach(($input) => {\n const targetId = $input.getAttribute('data-aria-controls')\n\n // Skip radios without data-aria-controls attributes\n if (!targetId) {\n return\n }\n\n // Throw if target conditional element does not exist.\n if (!document.getElementById(targetId)) {\n throw new ElementError({\n component: Checkboxes,\n identifier: `Conditional reveal (\\`id=\"${targetId}\"\\`)`\n })\n }\n\n // Promote the data-aria-controls attribute to a aria-controls attribute\n // so that the relationship is exposed in the AOM\n $input.setAttribute('aria-controls', targetId)\n $input.removeAttribute('data-aria-controls')\n })\n\n // When the page is restored after navigating 'back' in some browsers the\n // state of form controls is not restored until *after* the DOMContentLoaded\n // event is fired, so we need to sync after the pageshow event.\n window.addEventListener('pageshow', () => this.syncAllConditionalReveals())\n\n // Although we've set up handlers to sync state on the pageshow event, init\n // could be called after those events have fired, for example if they are\n // added to the page dynamically, so sync now too.\n this.syncAllConditionalReveals()\n\n // Handle events\n this.$root.addEventListener('click', (event) => this.handleClick(event))\n }\n\n /**\n * Sync the conditional reveal states for all checkboxes in this component.\n *\n * @private\n */\n syncAllConditionalReveals() {\n this.$inputs.forEach(($input) =>\n this.syncConditionalRevealWithInputState($input)\n )\n }\n\n /**\n * Sync conditional reveal with the input state\n *\n * Synchronise the visibility of the conditional reveal, and its accessible\n * state, with the input's checked state.\n *\n * @private\n * @param {HTMLInputElement} $input - Checkbox input\n */\n syncConditionalRevealWithInputState($input) {\n const targetId = $input.getAttribute('aria-controls')\n if (!targetId) {\n return\n }\n\n const $target = document.getElementById(targetId)\n if ($target?.classList.contains('govuk-checkboxes__conditional')) {\n const inputIsChecked = $input.checked\n\n $input.setAttribute('aria-expanded', inputIsChecked.toString())\n $target.classList.toggle(\n 'govuk-checkboxes__conditional--hidden',\n !inputIsChecked\n )\n }\n }\n\n /**\n * Uncheck other checkboxes\n *\n * Find any other checkbox inputs with the same name value, and uncheck them.\n * This is useful for when a “None of these\" checkbox is checked.\n *\n * @private\n * @param {HTMLInputElement} $input - Checkbox input\n */\n unCheckAllInputsExcept($input) {\n const allInputsWithSameName = document.querySelectorAll(\n `input[type=\"checkbox\"][name=\"${$input.name}\"]`\n )\n\n allInputsWithSameName.forEach(($inputWithSameName) => {\n const hasSameFormOwner = $input.form === $inputWithSameName.form\n if (hasSameFormOwner && $inputWithSameName !== $input) {\n $inputWithSameName.checked = false\n this.syncConditionalRevealWithInputState($inputWithSameName)\n }\n })\n }\n\n /**\n * Uncheck exclusive checkboxes\n *\n * Find any checkbox inputs with the same name value and the 'exclusive'\n * behaviour, and uncheck them. This helps prevent someone checking both a\n * regular checkbox and a \"None of these\" checkbox in the same fieldset.\n *\n * @private\n * @param {HTMLInputElement} $input - Checkbox input\n */\n unCheckExclusiveInputs($input) {\n const allInputsWithSameNameAndExclusiveBehaviour =\n document.querySelectorAll(\n `input[data-behaviour=\"exclusive\"][type=\"checkbox\"][name=\"${$input.name}\"]`\n )\n\n allInputsWithSameNameAndExclusiveBehaviour.forEach(($exclusiveInput) => {\n const hasSameFormOwner = $input.form === $exclusiveInput.form\n if (hasSameFormOwner) {\n $exclusiveInput.checked = false\n this.syncConditionalRevealWithInputState($exclusiveInput)\n }\n })\n }\n\n /**\n * Click event handler\n *\n * Handle a click within the component root – if the click occurred on a checkbox,\n * sync the state of any associated conditional reveal with the checkbox\n * state.\n *\n * @private\n * @param {MouseEvent} event - Click event\n */\n handleClick(event) {\n const $clickedInput = event.target\n\n // Ignore clicks on things that aren't checkbox inputs\n if (\n !($clickedInput instanceof HTMLInputElement) ||\n $clickedInput.type !== 'checkbox'\n ) {\n return\n }\n\n // If the checkbox conditionally-reveals some content, sync the state\n const hasAriaControls = $clickedInput.getAttribute('aria-controls')\n if (hasAriaControls) {\n this.syncConditionalRevealWithInputState($clickedInput)\n }\n\n // No further behaviour needed for unchecking\n if (!$clickedInput.checked) {\n return\n }\n\n // Handle 'exclusive' checkbox behaviour (ie \"None of these\")\n const hasBehaviourExclusive =\n $clickedInput.getAttribute('data-behaviour') === 'exclusive'\n if (hasBehaviourExclusive) {\n this.unCheckAllInputsExcept($clickedInput)\n } else {\n this.unCheckExclusiveInputs($clickedInput)\n }\n }\n\n /**\n * Name for the component used when initialising using data-module attributes.\n */\n static moduleName = 'govuk-checkboxes'\n}\n"],"names":["isInitialised","$root","moduleName","HTMLElement","hasAttribute","isSupported","$scope","document","body","classList","contains","formatErrorMessage","Component","message","GOVUKFrontendError","Error","constructor","args","name","SupportError","supportMessage","HTMLScriptElement","prototype","ElementError","messageOrOptions","component","identifier","element","expectedType","InitError","componentOrMessage","GOVUKFrontendComponent","_$root","childConstructor","elementType","checkSupport","checkInitialised","setAttribute","Checkboxes","$inputs","querySelectorAll","length","forEach","$input","targetId","getAttribute","getElementById","removeAttribute","window","addEventListener","syncAllConditionalReveals","event","handleClick","syncConditionalRevealWithInputState","$target","inputIsChecked","checked","toString","toggle","unCheckAllInputsExcept","allInputsWithSameName","$inputWithSameName","hasSameFormOwner","form","unCheckExclusiveInputs","allInputsWithSameNameAndExclusiveBehaviour","$exclusiveInput","$clickedInput","target","HTMLInputElement","type","hasAriaControls","hasBehaviourExclusive"],"mappings":"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"}
1
+ {"version":3,"file":"checkboxes.bundle.js","sources":["../../../../src/govuk/common/index.mjs","../../../../src/govuk/errors/index.mjs","../../../../src/govuk/govuk-frontend-component.mjs","../../../../src/govuk/components/checkboxes/checkboxes.mjs"],"sourcesContent":["/**\n * Common helpers which do not require polyfill.\n *\n * IMPORTANT: If a helper require a polyfill, please isolate it in its own module\n * so that the polyfill can be properly tree-shaken and does not burden\n * the components that do not need that helper\n */\n\n/**\n * Get hash fragment from URL\n *\n * Extract the hash fragment (everything after the hash) from a URL,\n * but not including the hash symbol\n *\n * @private\n * @param {string} url - URL\n * @returns {string | undefined} Fragment from URL, without the hash\n */\nexport function getFragmentFromUrl(url) {\n if (!url.includes('#')) {\n return undefined\n }\n\n return url.split('#').pop()\n}\n\n/**\n * Get GOV.UK Frontend breakpoint value from CSS custom property\n *\n * @private\n * @param {string} name - Breakpoint name\n * @returns {{ property: string, value?: string }} Breakpoint object\n */\nexport function getBreakpoint(name) {\n const property = `--govuk-frontend-breakpoint-${name}`\n\n // Get value from `<html>` with breakpoints on CSS :root\n const value = window\n .getComputedStyle(document.documentElement)\n .getPropertyValue(property)\n\n return {\n property,\n value: value || undefined\n }\n}\n\n/**\n * Move focus to element\n *\n * Sets tabindex to -1 to make the element programmatically focusable,\n * but removes it on blur as the element doesn't need to be focused again.\n *\n * @private\n * @template {HTMLElement} FocusElement\n * @param {FocusElement} $element - HTML element\n * @param {object} [options] - Handler options\n * @param {function(this: FocusElement): void} [options.onBeforeFocus] - Callback before focus\n * @param {function(this: FocusElement): void} [options.onBlur] - Callback on blur\n */\nexport function setFocus($element, options = {}) {\n const isFocusable = $element.getAttribute('tabindex')\n\n if (!isFocusable) {\n $element.setAttribute('tabindex', '-1')\n }\n\n /**\n * Handle element focus\n */\n function onFocus() {\n $element.addEventListener('blur', onBlur, { once: true })\n }\n\n /**\n * Handle element blur\n */\n function onBlur() {\n options.onBlur?.call($element)\n\n if (!isFocusable) {\n $element.removeAttribute('tabindex')\n }\n }\n\n // Add listener to reset element on blur, after focus\n $element.addEventListener('focus', onFocus, { once: true })\n\n // Focus element\n options.onBeforeFocus?.call($element)\n $element.focus()\n}\n\n/**\n * Checks if component is already initialised\n *\n * @internal\n * @param {Element} $root - HTML element to be checked\n * @param {string} moduleName - name of component module\n * @returns {boolean} Whether component is already initialised\n */\nexport function isInitialised($root, moduleName) {\n return (\n $root instanceof HTMLElement &&\n $root.hasAttribute(`data-${moduleName}-init`)\n )\n}\n\n/**\n * Checks if GOV.UK Frontend is supported on this page\n *\n * Some browsers will load and run our JavaScript but GOV.UK Frontend\n * won't be supported.\n *\n * @param {HTMLElement | null} [$scope] - (internal) `<body>` HTML element checked for browser support\n * @returns {boolean} Whether GOV.UK Frontend is supported on this page\n */\nexport function isSupported($scope = document.body) {\n if (!$scope) {\n return false\n }\n\n return $scope.classList.contains('govuk-frontend-supported')\n}\n\n/**\n * Check for an array\n *\n * @internal\n * @param {unknown} option - Option to check\n * @returns {boolean} Whether the option is an array\n */\nfunction isArray(option) {\n return Array.isArray(option)\n}\n\n/**\n * Check for an object\n *\n * @internal\n * @param {unknown} option - Option to check\n * @returns {boolean} Whether the option is an object\n */\nexport function isObject(option) {\n return !!option && typeof option === 'object' && !isArray(option)\n}\n\n/**\n * Format error message\n *\n * @internal\n * @param {ComponentWithModuleName} Component - Component that threw the error\n * @param {string} message - Error message\n * @returns {string} - Formatted error message\n */\nexport function formatErrorMessage(Component, message) {\n return `${Component.moduleName}: ${message}`\n}\n\n/* eslint-disable jsdoc/valid-types --\n * `{new(...args: any[] ): object}` is not recognised as valid\n * https://github.com/gajus/eslint-plugin-jsdoc/issues/145#issuecomment-1308722878\n * https://github.com/jsdoc-type-pratt-parser/jsdoc-type-pratt-parser/issues/131\n **/\n\n/**\n * @typedef ComponentWithModuleName\n * @property {string} moduleName - Name of the component\n */\n\n/* eslint-enable jsdoc/valid-types */\n","import { formatErrorMessage } from '../common/index.mjs'\n\n/**\n * GOV.UK Frontend error\n *\n * A base class for `Error`s thrown by GOV.UK Frontend.\n *\n * It is meant to be extended into specific types of errors\n * to be thrown by our code.\n *\n * @example\n * ```js\n * class MissingRootError extends GOVUKFrontendError {\n * // Setting an explicit name is important as extending the class will not\n * // set a new `name` on the subclass. The `name` property is important\n * // to ensure intelligible error names even if the class name gets\n * // mangled by a minifier\n * name = \"MissingRootError\"\n * }\n * ```\n * @virtual\n */\nexport class GOVUKFrontendError extends Error {\n name = 'GOVUKFrontendError'\n}\n\n/**\n * Indicates that GOV.UK Frontend is not supported\n */\nexport class SupportError extends GOVUKFrontendError {\n name = 'SupportError'\n\n /**\n * Checks if GOV.UK Frontend is supported on this page\n *\n * @param {HTMLElement | null} [$scope] - HTML element `<body>` checked for browser support\n */\n constructor($scope = document.body) {\n const supportMessage =\n 'noModule' in HTMLScriptElement.prototype\n ? 'GOV.UK Frontend initialised without `<body class=\"govuk-frontend-supported\">` from template `<script>` snippet'\n : 'GOV.UK Frontend is not supported in this browser'\n\n super(\n $scope\n ? supportMessage\n : 'GOV.UK Frontend initialised without `<script type=\"module\">`'\n )\n }\n}\n\n/**\n * Indicates that a component has received an illegal configuration\n */\nexport class ConfigError extends GOVUKFrontendError {\n name = 'ConfigError'\n}\n\n/**\n * Indicates an issue with an element (possibly `null` or `undefined`)\n */\nexport class ElementError extends GOVUKFrontendError {\n name = 'ElementError'\n\n /**\n * @internal\n * @overload\n * @param {string} message - Element error message\n */\n\n /**\n * @internal\n * @overload\n * @param {ElementErrorOptions} options - Element error options\n */\n\n /**\n * @internal\n * @param {string | ElementErrorOptions} messageOrOptions - Element error message or options\n */\n constructor(messageOrOptions) {\n let message = typeof messageOrOptions === 'string' ? messageOrOptions : ''\n\n // Build message from options\n if (typeof messageOrOptions === 'object') {\n const { component, identifier, element, expectedType } = messageOrOptions\n\n message = identifier\n\n // Append reason\n message += element\n ? ` is not of type ${expectedType ?? 'HTMLElement'}`\n : ' not found'\n\n message = formatErrorMessage(component, message)\n }\n\n super(message)\n }\n}\n\n/**\n * Indicates that a component is already initialised\n */\nexport class InitError extends GOVUKFrontendError {\n name = 'InitError'\n\n /**\n * @internal\n * @param {ComponentWithModuleName | string} componentOrMessage - name of the component module\n */\n constructor(componentOrMessage) {\n const message =\n typeof componentOrMessage === 'string'\n ? componentOrMessage\n : formatErrorMessage(\n componentOrMessage,\n `Root element (\\`$root\\`) already initialised`\n )\n\n super(message)\n }\n}\n\n/**\n * Element error options\n *\n * @internal\n * @typedef {object} ElementErrorOptions\n * @property {string} identifier - An identifier that'll let the user understand which element has an error. This is whatever makes the most sense\n * @property {Element | null} [element] - The element in error\n * @property {string} [expectedType] - The type that was expected for the identifier\n * @property {ComponentWithModuleName} component - Component throwing the error\n */\n\n/**\n * @typedef {import('../common/index.mjs').ComponentWithModuleName} ComponentWithModuleName\n */\n","import { isInitialised, isSupported } from './common/index.mjs'\nimport { ElementError, InitError, SupportError } from './errors/index.mjs'\n\n/**\n * Base Component class\n *\n * Centralises the behaviours shared by our components\n *\n * @virtual\n * @template {Element} [RootElementType=HTMLElement]\n */\nexport class GOVUKFrontendComponent {\n /**\n * @type {typeof Element}\n */\n static elementType = HTMLElement\n\n // allows Typescript user to work around the lack of types\n // in GOVUKFrontend package, Typescript is not aware of $root\n // in components that extend GOVUKFrontendComponent\n /**\n * Returns the root element of the component\n *\n * @protected\n * @returns {RootElementType} - the root element of component\n */\n get $root() {\n return this._$root\n }\n\n /**\n * @protected\n * @type {RootElementType}\n */\n _$root\n\n /**\n * Constructs a new component, validating that GOV.UK Frontend is supported\n *\n * @internal\n * @param {Element | null} [$root] - HTML element to use for component\n */\n constructor($root) {\n const childConstructor = /** @type {ChildClassConstructor} */ (\n this.constructor\n )\n\n // TypeScript does not enforce that inheriting classes will define a `moduleName`\n // (even if we add a `@virtual` `static moduleName` property to this class).\n // While we trust users to do this correctly, we do a little check to provide them\n // a helpful error message.\n //\n // After this, we'll be sure that `childConstructor` has a `moduleName`\n // as expected of the `ChildClassConstructor` we've cast `this.constructor` to.\n if (typeof childConstructor.moduleName !== 'string') {\n throw new InitError(`\\`moduleName\\` not defined in component`)\n }\n\n if (!($root instanceof childConstructor.elementType)) {\n throw new ElementError({\n element: $root,\n component: childConstructor,\n identifier: 'Root element (`$root`)',\n expectedType: childConstructor.elementType.name\n })\n } else {\n this._$root = /** @type {RootElementType} */ ($root)\n }\n\n childConstructor.checkSupport()\n\n this.checkInitialised()\n\n const moduleName = childConstructor.moduleName\n\n this.$root.setAttribute(`data-${moduleName}-init`, '')\n }\n\n /**\n * Validates whether component is already initialised\n *\n * @private\n * @throws {InitError} when component is already initialised\n */\n checkInitialised() {\n const constructor = /** @type {ChildClassConstructor} */ (this.constructor)\n const moduleName = constructor.moduleName\n\n if (moduleName && isInitialised(this.$root, moduleName)) {\n throw new InitError(constructor)\n }\n }\n\n /**\n * Validates whether components are supported\n *\n * @throws {SupportError} when the components are not supported\n */\n static checkSupport() {\n if (!isSupported()) {\n throw new SupportError()\n }\n }\n}\n\n/**\n * @typedef ChildClass\n * @property {string} moduleName - The module name that'll be looked for in the DOM when initialising the component\n */\n\n/**\n * @typedef {typeof GOVUKFrontendComponent & ChildClass} ChildClassConstructor\n */\n","import { ElementError } from '../../errors/index.mjs'\nimport { GOVUKFrontendComponent } from '../../govuk-frontend-component.mjs'\n\n/**\n * Checkboxes component\n *\n * @preserve\n */\nexport class Checkboxes extends GOVUKFrontendComponent {\n /** @private */\n $inputs\n\n /**\n * Checkboxes can be associated with a 'conditionally revealed' content block\n * – for example, a checkbox for 'Phone' could reveal an additional form field\n * for the user to enter their phone number.\n *\n * These associations are made using a `data-aria-controls` attribute, which\n * is promoted to an aria-controls attribute during initialisation.\n *\n * We also need to restore the state of any conditional reveals on the page\n * (for example if the user has navigated back), and set up event handlers to\n * keep the reveal in sync with the checkbox state.\n *\n * @param {Element | null} $root - HTML element to use for checkboxes\n */\n constructor($root) {\n super($root)\n\n const $inputs = this.$root.querySelectorAll('input[type=\"checkbox\"]')\n if (!$inputs.length) {\n throw new ElementError({\n component: Checkboxes,\n identifier: 'Form inputs (`<input type=\"checkbox\">`)'\n })\n }\n\n this.$inputs = $inputs\n\n this.$inputs.forEach(($input) => {\n const targetId = $input.getAttribute('data-aria-controls')\n\n // Skip radios without data-aria-controls attributes\n if (!targetId) {\n return\n }\n\n // Throw if target conditional element does not exist.\n if (!document.getElementById(targetId)) {\n throw new ElementError({\n component: Checkboxes,\n identifier: `Conditional reveal (\\`id=\"${targetId}\"\\`)`\n })\n }\n\n // Promote the data-aria-controls attribute to a aria-controls attribute\n // so that the relationship is exposed in the AOM\n $input.setAttribute('aria-controls', targetId)\n $input.removeAttribute('data-aria-controls')\n })\n\n // When the page is restored after navigating 'back' in some browsers the\n // state of form controls is not restored until *after* the DOMContentLoaded\n // event is fired, so we need to sync after the pageshow event.\n window.addEventListener('pageshow', () => this.syncAllConditionalReveals())\n\n // Although we've set up handlers to sync state on the pageshow event, init\n // could be called after those events have fired, for example if they are\n // added to the page dynamically, so sync now too.\n this.syncAllConditionalReveals()\n\n // Handle events\n this.$root.addEventListener('click', (event) => this.handleClick(event))\n }\n\n /**\n * Sync the conditional reveal states for all checkboxes in this component.\n *\n * @private\n */\n syncAllConditionalReveals() {\n this.$inputs.forEach(($input) =>\n this.syncConditionalRevealWithInputState($input)\n )\n }\n\n /**\n * Sync conditional reveal with the input state\n *\n * Synchronise the visibility of the conditional reveal, and its accessible\n * state, with the input's checked state.\n *\n * @private\n * @param {HTMLInputElement} $input - Checkbox input\n */\n syncConditionalRevealWithInputState($input) {\n const targetId = $input.getAttribute('aria-controls')\n if (!targetId) {\n return\n }\n\n const $target = document.getElementById(targetId)\n if ($target?.classList.contains('govuk-checkboxes__conditional')) {\n const inputIsChecked = $input.checked\n\n $input.setAttribute('aria-expanded', inputIsChecked.toString())\n $target.classList.toggle(\n 'govuk-checkboxes__conditional--hidden',\n !inputIsChecked\n )\n }\n }\n\n /**\n * Uncheck other checkboxes\n *\n * Find any other checkbox inputs with the same name value, and uncheck them.\n * This is useful for when a “None of these\" checkbox is checked.\n *\n * @private\n * @param {HTMLInputElement} $input - Checkbox input\n */\n unCheckAllInputsExcept($input) {\n const allInputsWithSameName = document.querySelectorAll(\n `input[type=\"checkbox\"][name=\"${$input.name}\"]`\n )\n\n allInputsWithSameName.forEach(($inputWithSameName) => {\n const hasSameFormOwner = $input.form === $inputWithSameName.form\n if (hasSameFormOwner && $inputWithSameName !== $input) {\n $inputWithSameName.checked = false\n this.syncConditionalRevealWithInputState($inputWithSameName)\n }\n })\n }\n\n /**\n * Uncheck exclusive checkboxes\n *\n * Find any checkbox inputs with the same name value and the 'exclusive'\n * behaviour, and uncheck them. This helps prevent someone checking both a\n * regular checkbox and a \"None of these\" checkbox in the same fieldset.\n *\n * @private\n * @param {HTMLInputElement} $input - Checkbox input\n */\n unCheckExclusiveInputs($input) {\n const allInputsWithSameNameAndExclusiveBehaviour =\n document.querySelectorAll(\n `input[data-behaviour=\"exclusive\"][type=\"checkbox\"][name=\"${$input.name}\"]`\n )\n\n allInputsWithSameNameAndExclusiveBehaviour.forEach(($exclusiveInput) => {\n const hasSameFormOwner = $input.form === $exclusiveInput.form\n if (hasSameFormOwner) {\n $exclusiveInput.checked = false\n this.syncConditionalRevealWithInputState($exclusiveInput)\n }\n })\n }\n\n /**\n * Click event handler\n *\n * Handle a click within the component root – if the click occurred on a checkbox,\n * sync the state of any associated conditional reveal with the checkbox\n * state.\n *\n * @private\n * @param {MouseEvent} event - Click event\n */\n handleClick(event) {\n const $clickedInput = event.target\n\n // Ignore clicks on things that aren't checkbox inputs\n if (\n !($clickedInput instanceof HTMLInputElement) ||\n $clickedInput.type !== 'checkbox'\n ) {\n return\n }\n\n // If the checkbox conditionally-reveals some content, sync the state\n const hasAriaControls = $clickedInput.getAttribute('aria-controls')\n if (hasAriaControls) {\n this.syncConditionalRevealWithInputState($clickedInput)\n }\n\n // No further behaviour needed for unchecking\n if (!$clickedInput.checked) {\n return\n }\n\n // Handle 'exclusive' checkbox behaviour (ie \"None of these\")\n const hasBehaviourExclusive =\n $clickedInput.getAttribute('data-behaviour') === 'exclusive'\n if (hasBehaviourExclusive) {\n this.unCheckAllInputsExcept($clickedInput)\n } else {\n this.unCheckExclusiveInputs($clickedInput)\n }\n }\n\n /**\n * Name for the component used when initialising using data-module attributes.\n */\n static moduleName = 'govuk-checkboxes'\n}\n"],"names":["isInitialised","$root","moduleName","HTMLElement","hasAttribute","isSupported","$scope","document","body","classList","contains","formatErrorMessage","Component","message","GOVUKFrontendError","Error","constructor","args","name","SupportError","supportMessage","HTMLScriptElement","prototype","ElementError","messageOrOptions","component","identifier","element","expectedType","InitError","componentOrMessage","GOVUKFrontendComponent","_$root","childConstructor","elementType","checkSupport","checkInitialised","setAttribute","Checkboxes","$inputs","querySelectorAll","length","forEach","$input","targetId","getAttribute","getElementById","removeAttribute","window","addEventListener","syncAllConditionalReveals","event","handleClick","syncConditionalRevealWithInputState","$target","inputIsChecked","checked","toString","toggle","unCheckAllInputsExcept","allInputsWithSameName","$inputWithSameName","hasSameFormOwner","form","unCheckExclusiveInputs","allInputsWithSameNameAndExclusiveBehaviour","$exclusiveInput","$clickedInput","target","HTMLInputElement","type","hasAriaControls","hasBehaviourExclusive"],"mappings":"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"}
@@ -20,29 +20,6 @@ function isSupported($scope = document.body) {
20
20
  function formatErrorMessage(Component, message) {
21
21
  return `${Component.moduleName}: ${message}`;
22
22
  }
23
-
24
- /**
25
- * Schema for component config
26
- *
27
- * @typedef {object} Schema
28
- * @property {{ [field: string]: SchemaProperty | undefined }} properties - Schema properties
29
- * @property {SchemaCondition[]} [anyOf] - List of schema conditions
30
- */
31
-
32
- /**
33
- * Schema property for component config
34
- *
35
- * @typedef {object} SchemaProperty
36
- * @property {'string' | 'boolean' | 'number' | 'object'} type - Property type
37
- */
38
-
39
- /**
40
- * Schema condition for component config
41
- *
42
- * @typedef {object} SchemaCondition
43
- * @property {string[]} required - List of required config fields
44
- * @property {string} errorMessage - Error message when required config fields not provided
45
- */
46
23
  /**
47
24
  * @typedef ComponentWithModuleName
48
25
  * @property {string} moduleName - Name of the component
@@ -1 +1 @@
1
- {"version":3,"file":"checkboxes.bundle.mjs","sources":["../../../../src/govuk/common/index.mjs","../../../../src/govuk/errors/index.mjs","../../../../src/govuk/govuk-frontend-component.mjs","../../../../src/govuk/components/checkboxes/checkboxes.mjs"],"sourcesContent":["import { normaliseString } from './normalise-string.mjs'\n\n/**\n * Common helpers which do not require polyfill.\n *\n * IMPORTANT: If a helper require a polyfill, please isolate it in its own module\n * so that the polyfill can be properly tree-shaken and does not burden\n * the components that do not need that helper\n */\n\n/**\n * Config merging function\n *\n * Takes any number of objects and combines them together, with\n * greatest priority on the LAST item passed in.\n *\n * @internal\n * @param {...{ [key: string]: unknown }} configObjects - Config objects to merge\n * @returns {{ [key: string]: unknown }} A merged config object\n */\nexport function mergeConfigs(...configObjects) {\n // Start with an empty object as our base\n /** @type {{ [key: string]: unknown }} */\n const formattedConfigObject = {}\n\n // Loop through each of the passed objects\n for (const configObject of configObjects) {\n for (const key of Object.keys(configObject)) {\n const option = formattedConfigObject[key]\n const override = configObject[key]\n\n // Push their keys one-by-one into formattedConfigObject. Any duplicate\n // keys with object values will be merged, otherwise the new value will\n // override the existing value.\n if (isObject(option) && isObject(override)) {\n // @ts-expect-error Index signature for type 'string' is missing\n formattedConfigObject[key] = mergeConfigs(option, override)\n } else {\n // Apply override\n formattedConfigObject[key] = override\n }\n }\n }\n\n return formattedConfigObject\n}\n\n/**\n * Extracts keys starting with a particular namespace from dataset ('data-*')\n * object, removing the namespace in the process, normalising all values\n *\n * @internal\n * @param {{ schema: Schema }} Component - Component class\n * @param {DOMStringMap} dataset - The object to extract key-value pairs from\n * @param {string} namespace - The namespace to filter keys with\n * @returns {ObjectNested | undefined} Nested object with dot-separated key namespace removed\n */\nexport function extractConfigByNamespace(Component, dataset, namespace) {\n const property = Component.schema.properties[namespace]\n\n // Only extract configs for object schema properties\n if (property?.type !== 'object') {\n return\n }\n\n // Add default empty config\n const newObject = {\n [namespace]: /** @type {ObjectNested} */ ({})\n }\n\n for (const [key, value] of Object.entries(dataset)) {\n /** @type {ObjectNested | ObjectNested[NestedKey]} */\n let current = newObject\n\n // Split the key into parts, using . as our namespace separator\n const keyParts = key.split('.')\n\n /**\n * Create new level per part\n *\n * e.g. 'i18n.textareaDescription.other' becomes\n * `{ i18n: { textareaDescription: { other } } }`\n */\n for (const [index, name] of keyParts.entries()) {\n if (typeof current === 'object') {\n // Drop down to nested object until the last part\n if (index < keyParts.length - 1) {\n // New nested object (optionally) replaces existing value\n if (!isObject(current[name])) {\n current[name] = {}\n }\n\n // Drop down into new or existing nested object\n current = current[name]\n } else if (key !== namespace) {\n // Normalised value (optionally) replaces existing value\n current[name] = normaliseString(value)\n }\n }\n }\n }\n\n return newObject[namespace]\n}\n\n/**\n * Get hash fragment from URL\n *\n * Extract the hash fragment (everything after the hash) from a URL,\n * but not including the hash symbol\n *\n * @private\n * @param {string} url - URL\n * @returns {string | undefined} Fragment from URL, without the hash\n */\nexport function getFragmentFromUrl(url) {\n if (!url.includes('#')) {\n return undefined\n }\n\n return url.split('#').pop()\n}\n\n/**\n * Get GOV.UK Frontend breakpoint value from CSS custom property\n *\n * @private\n * @param {string} name - Breakpoint name\n * @returns {{ property: string, value?: string }} Breakpoint object\n */\nexport function getBreakpoint(name) {\n const property = `--govuk-frontend-breakpoint-${name}`\n\n // Get value from `<html>` with breakpoints on CSS :root\n const value = window\n .getComputedStyle(document.documentElement)\n .getPropertyValue(property)\n\n return {\n property,\n value: value || undefined\n }\n}\n\n/**\n * Move focus to element\n *\n * Sets tabindex to -1 to make the element programmatically focusable,\n * but removes it on blur as the element doesn't need to be focused again.\n *\n * @private\n * @template {HTMLElement} FocusElement\n * @param {FocusElement} $element - HTML element\n * @param {object} [options] - Handler options\n * @param {function(this: FocusElement): void} [options.onBeforeFocus] - Callback before focus\n * @param {function(this: FocusElement): void} [options.onBlur] - Callback on blur\n */\nexport function setFocus($element, options = {}) {\n const isFocusable = $element.getAttribute('tabindex')\n\n if (!isFocusable) {\n $element.setAttribute('tabindex', '-1')\n }\n\n /**\n * Handle element focus\n */\n function onFocus() {\n $element.addEventListener('blur', onBlur, { once: true })\n }\n\n /**\n * Handle element blur\n */\n function onBlur() {\n options.onBlur?.call($element)\n\n if (!isFocusable) {\n $element.removeAttribute('tabindex')\n }\n }\n\n // Add listener to reset element on blur, after focus\n $element.addEventListener('focus', onFocus, { once: true })\n\n // Focus element\n options.onBeforeFocus?.call($element)\n $element.focus()\n}\n\n/**\n * Checks if component is already initialised\n *\n * @internal\n * @param {Element} $root - HTML element to be checked\n * @param {string} moduleName - name of component module\n * @returns {boolean} Whether component is already initialised\n */\nexport function isInitialised($root, moduleName) {\n return (\n $root instanceof HTMLElement &&\n $root.hasAttribute(`data-${moduleName}-init`)\n )\n}\n\n/**\n * Checks if GOV.UK Frontend is supported on this page\n *\n * Some browsers will load and run our JavaScript but GOV.UK Frontend\n * won't be supported.\n *\n * @param {HTMLElement | null} [$scope] - (internal) `<body>` HTML element checked for browser support\n * @returns {boolean} Whether GOV.UK Frontend is supported on this page\n */\nexport function isSupported($scope = document.body) {\n if (!$scope) {\n return false\n }\n\n return $scope.classList.contains('govuk-frontend-supported')\n}\n\n/**\n * Validate component config by schema\n *\n * Follows limited examples in JSON schema for wider support in future\n *\n * {@link https://ajv.js.org/json-schema.html#compound-keywords}\n * {@link https://ajv.js.org/packages/ajv-errors.html#single-message}\n *\n * @internal\n * @param {Schema} schema - Config schema\n * @param {{ [key: string]: unknown }} config - Component config\n * @returns {string[]} List of validation errors\n */\nexport function validateConfig(schema, config) {\n const validationErrors = []\n\n // Check errors for each schema\n for (const [name, conditions] of Object.entries(schema)) {\n const errors = []\n\n // Check errors for each schema condition\n if (Array.isArray(conditions)) {\n for (const { required, errorMessage } of conditions) {\n if (!required.every((key) => !!config[key])) {\n errors.push(errorMessage) // Missing config key value\n }\n }\n\n // Check one condition passes or add errors\n if (name === 'anyOf' && !(conditions.length - errors.length >= 1)) {\n validationErrors.push(...errors)\n }\n }\n }\n\n return validationErrors\n}\n\n/**\n * Check for an array\n *\n * @internal\n * @param {unknown} option - Option to check\n * @returns {boolean} Whether the option is an array\n */\nfunction isArray(option) {\n return Array.isArray(option)\n}\n\n/**\n * Check for an object\n *\n * @internal\n * @param {unknown} option - Option to check\n * @returns {boolean} Whether the option is an object\n */\nfunction isObject(option) {\n return !!option && typeof option === 'object' && !isArray(option)\n}\n\n/**\n * Format error message\n *\n * @internal\n * @param {ComponentWithModuleName} Component - Component that threw the error\n * @param {string} message - Error message\n * @returns {string} - Formatted error message\n */\nexport function formatErrorMessage(Component, message) {\n return `${Component.moduleName}: ${message}`\n}\n\n/**\n * Schema for component config\n *\n * @typedef {object} Schema\n * @property {{ [field: string]: SchemaProperty | undefined }} properties - Schema properties\n * @property {SchemaCondition[]} [anyOf] - List of schema conditions\n */\n\n/**\n * Schema property for component config\n *\n * @typedef {object} SchemaProperty\n * @property {'string' | 'boolean' | 'number' | 'object'} type - Property type\n */\n\n/**\n * Schema condition for component config\n *\n * @typedef {object} SchemaCondition\n * @property {string[]} required - List of required config fields\n * @property {string} errorMessage - Error message when required config fields not provided\n */\n\n/**\n * @internal\n * @typedef {keyof ObjectNested} NestedKey\n * @typedef {{ [key: string]: string | boolean | number | ObjectNested | undefined }} ObjectNested\n */\n\n/* eslint-disable jsdoc/valid-types --\n * `{new(...args: any[] ): object}` is not recognised as valid\n * https://github.com/gajus/eslint-plugin-jsdoc/issues/145#issuecomment-1308722878\n * https://github.com/jsdoc-type-pratt-parser/jsdoc-type-pratt-parser/issues/131\n **/\n\n/**\n * @typedef ComponentWithModuleName\n * @property {string} moduleName - Name of the component\n */\n\n/* eslint-enable jsdoc/valid-types */\n","import { formatErrorMessage } from '../common/index.mjs'\n\n/**\n * GOV.UK Frontend error\n *\n * A base class for `Error`s thrown by GOV.UK Frontend.\n *\n * It is meant to be extended into specific types of errors\n * to be thrown by our code.\n *\n * @example\n * ```js\n * class MissingRootError extends GOVUKFrontendError {\n * // Setting an explicit name is important as extending the class will not\n * // set a new `name` on the subclass. The `name` property is important\n * // to ensure intelligible error names even if the class name gets\n * // mangled by a minifier\n * name = \"MissingRootError\"\n * }\n * ```\n * @virtual\n */\nexport class GOVUKFrontendError extends Error {\n name = 'GOVUKFrontendError'\n}\n\n/**\n * Indicates that GOV.UK Frontend is not supported\n */\nexport class SupportError extends GOVUKFrontendError {\n name = 'SupportError'\n\n /**\n * Checks if GOV.UK Frontend is supported on this page\n *\n * @param {HTMLElement | null} [$scope] - HTML element `<body>` checked for browser support\n */\n constructor($scope = document.body) {\n const supportMessage =\n 'noModule' in HTMLScriptElement.prototype\n ? 'GOV.UK Frontend initialised without `<body class=\"govuk-frontend-supported\">` from template `<script>` snippet'\n : 'GOV.UK Frontend is not supported in this browser'\n\n super(\n $scope\n ? supportMessage\n : 'GOV.UK Frontend initialised without `<script type=\"module\">`'\n )\n }\n}\n\n/**\n * Indicates that a component has received an illegal configuration\n */\nexport class ConfigError extends GOVUKFrontendError {\n name = 'ConfigError'\n}\n\n/**\n * Indicates an issue with an element (possibly `null` or `undefined`)\n */\nexport class ElementError extends GOVUKFrontendError {\n name = 'ElementError'\n\n /**\n * @internal\n * @overload\n * @param {string} message - Element error message\n */\n\n /**\n * @internal\n * @overload\n * @param {ElementErrorOptions} options - Element error options\n */\n\n /**\n * @internal\n * @param {string | ElementErrorOptions} messageOrOptions - Element error message or options\n */\n constructor(messageOrOptions) {\n let message = typeof messageOrOptions === 'string' ? messageOrOptions : ''\n\n // Build message from options\n if (typeof messageOrOptions === 'object') {\n const { component, identifier, element, expectedType } = messageOrOptions\n\n message = identifier\n\n // Append reason\n message += element\n ? ` is not of type ${expectedType ?? 'HTMLElement'}`\n : ' not found'\n\n message = formatErrorMessage(component, message)\n }\n\n super(message)\n }\n}\n\n/**\n * Indicates that a component is already initialised\n */\nexport class InitError extends GOVUKFrontendError {\n name = 'InitError'\n\n /**\n * @internal\n * @param {ComponentWithModuleName | string} componentOrMessage - name of the component module\n */\n constructor(componentOrMessage) {\n const message =\n typeof componentOrMessage === 'string'\n ? componentOrMessage\n : formatErrorMessage(\n componentOrMessage,\n `Root element (\\`$root\\`) already initialised`\n )\n\n super(message)\n }\n}\n\n/**\n * Element error options\n *\n * @internal\n * @typedef {object} ElementErrorOptions\n * @property {string} identifier - An identifier that'll let the user understand which element has an error. This is whatever makes the most sense\n * @property {Element | null} [element] - The element in error\n * @property {string} [expectedType] - The type that was expected for the identifier\n * @property {ComponentWithModuleName} component - Component throwing the error\n */\n\n/**\n * @typedef {import('../common/index.mjs').ComponentWithModuleName} ComponentWithModuleName\n */\n","import { isInitialised, isSupported } from './common/index.mjs'\nimport { ElementError, InitError, SupportError } from './errors/index.mjs'\n\n/**\n * Base Component class\n *\n * Centralises the behaviours shared by our components\n *\n * @virtual\n * @template {Element} [RootElementType=HTMLElement]\n */\nexport class GOVUKFrontendComponent {\n /**\n * @type {typeof Element}\n */\n static elementType = HTMLElement\n\n // allows Typescript user to work around the lack of types\n // in GOVUKFrontend package, Typescript is not aware of $root\n // in components that extend GOVUKFrontendComponent\n /**\n * Returns the root element of the component\n *\n * @protected\n * @returns {RootElementType} - the root element of component\n */\n get $root() {\n return this._$root\n }\n\n /**\n * @protected\n * @type {RootElementType}\n */\n _$root\n\n /**\n * Constructs a new component, validating that GOV.UK Frontend is supported\n *\n * @internal\n * @param {Element | null} [$root] - HTML element to use for component\n */\n constructor($root) {\n const childConstructor = /** @type {ChildClassConstructor} */ (\n this.constructor\n )\n\n // TypeScript does not enforce that inheriting classes will define a `moduleName`\n // (even if we add a `@virtual` `static moduleName` property to this class).\n // While we trust users to do this correctly, we do a little check to provide them\n // a helpful error message.\n //\n // After this, we'll be sure that `childConstructor` has a `moduleName`\n // as expected of the `ChildClassConstructor` we've cast `this.constructor` to.\n if (typeof childConstructor.moduleName !== 'string') {\n throw new InitError(`\\`moduleName\\` not defined in component`)\n }\n\n if (!($root instanceof childConstructor.elementType)) {\n throw new ElementError({\n element: $root,\n component: childConstructor,\n identifier: 'Root element (`$root`)',\n expectedType: childConstructor.elementType.name\n })\n } else {\n this._$root = /** @type {RootElementType} */ ($root)\n }\n\n childConstructor.checkSupport()\n\n this.checkInitialised()\n\n const moduleName = childConstructor.moduleName\n\n this.$root.setAttribute(`data-${moduleName}-init`, '')\n }\n\n /**\n * Validates whether component is already initialised\n *\n * @private\n * @throws {InitError} when component is already initialised\n */\n checkInitialised() {\n const constructor = /** @type {ChildClassConstructor} */ (this.constructor)\n const moduleName = constructor.moduleName\n\n if (moduleName && isInitialised(this.$root, moduleName)) {\n throw new InitError(constructor)\n }\n }\n\n /**\n * Validates whether components are supported\n *\n * @throws {SupportError} when the components are not supported\n */\n static checkSupport() {\n if (!isSupported()) {\n throw new SupportError()\n }\n }\n}\n\n/**\n * @typedef ChildClass\n * @property {string} moduleName - The module name that'll be looked for in the DOM when initialising the component\n */\n\n/**\n * @typedef {typeof GOVUKFrontendComponent & ChildClass} ChildClassConstructor\n */\n","import { ElementError } from '../../errors/index.mjs'\nimport { GOVUKFrontendComponent } from '../../govuk-frontend-component.mjs'\n\n/**\n * Checkboxes component\n *\n * @preserve\n */\nexport class Checkboxes extends GOVUKFrontendComponent {\n /** @private */\n $inputs\n\n /**\n * Checkboxes can be associated with a 'conditionally revealed' content block\n * – for example, a checkbox for 'Phone' could reveal an additional form field\n * for the user to enter their phone number.\n *\n * These associations are made using a `data-aria-controls` attribute, which\n * is promoted to an aria-controls attribute during initialisation.\n *\n * We also need to restore the state of any conditional reveals on the page\n * (for example if the user has navigated back), and set up event handlers to\n * keep the reveal in sync with the checkbox state.\n *\n * @param {Element | null} $root - HTML element to use for checkboxes\n */\n constructor($root) {\n super($root)\n\n const $inputs = this.$root.querySelectorAll('input[type=\"checkbox\"]')\n if (!$inputs.length) {\n throw new ElementError({\n component: Checkboxes,\n identifier: 'Form inputs (`<input type=\"checkbox\">`)'\n })\n }\n\n this.$inputs = $inputs\n\n this.$inputs.forEach(($input) => {\n const targetId = $input.getAttribute('data-aria-controls')\n\n // Skip radios without data-aria-controls attributes\n if (!targetId) {\n return\n }\n\n // Throw if target conditional element does not exist.\n if (!document.getElementById(targetId)) {\n throw new ElementError({\n component: Checkboxes,\n identifier: `Conditional reveal (\\`id=\"${targetId}\"\\`)`\n })\n }\n\n // Promote the data-aria-controls attribute to a aria-controls attribute\n // so that the relationship is exposed in the AOM\n $input.setAttribute('aria-controls', targetId)\n $input.removeAttribute('data-aria-controls')\n })\n\n // When the page is restored after navigating 'back' in some browsers the\n // state of form controls is not restored until *after* the DOMContentLoaded\n // event is fired, so we need to sync after the pageshow event.\n window.addEventListener('pageshow', () => this.syncAllConditionalReveals())\n\n // Although we've set up handlers to sync state on the pageshow event, init\n // could be called after those events have fired, for example if they are\n // added to the page dynamically, so sync now too.\n this.syncAllConditionalReveals()\n\n // Handle events\n this.$root.addEventListener('click', (event) => this.handleClick(event))\n }\n\n /**\n * Sync the conditional reveal states for all checkboxes in this component.\n *\n * @private\n */\n syncAllConditionalReveals() {\n this.$inputs.forEach(($input) =>\n this.syncConditionalRevealWithInputState($input)\n )\n }\n\n /**\n * Sync conditional reveal with the input state\n *\n * Synchronise the visibility of the conditional reveal, and its accessible\n * state, with the input's checked state.\n *\n * @private\n * @param {HTMLInputElement} $input - Checkbox input\n */\n syncConditionalRevealWithInputState($input) {\n const targetId = $input.getAttribute('aria-controls')\n if (!targetId) {\n return\n }\n\n const $target = document.getElementById(targetId)\n if ($target?.classList.contains('govuk-checkboxes__conditional')) {\n const inputIsChecked = $input.checked\n\n $input.setAttribute('aria-expanded', inputIsChecked.toString())\n $target.classList.toggle(\n 'govuk-checkboxes__conditional--hidden',\n !inputIsChecked\n )\n }\n }\n\n /**\n * Uncheck other checkboxes\n *\n * Find any other checkbox inputs with the same name value, and uncheck them.\n * This is useful for when a “None of these\" checkbox is checked.\n *\n * @private\n * @param {HTMLInputElement} $input - Checkbox input\n */\n unCheckAllInputsExcept($input) {\n const allInputsWithSameName = document.querySelectorAll(\n `input[type=\"checkbox\"][name=\"${$input.name}\"]`\n )\n\n allInputsWithSameName.forEach(($inputWithSameName) => {\n const hasSameFormOwner = $input.form === $inputWithSameName.form\n if (hasSameFormOwner && $inputWithSameName !== $input) {\n $inputWithSameName.checked = false\n this.syncConditionalRevealWithInputState($inputWithSameName)\n }\n })\n }\n\n /**\n * Uncheck exclusive checkboxes\n *\n * Find any checkbox inputs with the same name value and the 'exclusive'\n * behaviour, and uncheck them. This helps prevent someone checking both a\n * regular checkbox and a \"None of these\" checkbox in the same fieldset.\n *\n * @private\n * @param {HTMLInputElement} $input - Checkbox input\n */\n unCheckExclusiveInputs($input) {\n const allInputsWithSameNameAndExclusiveBehaviour =\n document.querySelectorAll(\n `input[data-behaviour=\"exclusive\"][type=\"checkbox\"][name=\"${$input.name}\"]`\n )\n\n allInputsWithSameNameAndExclusiveBehaviour.forEach(($exclusiveInput) => {\n const hasSameFormOwner = $input.form === $exclusiveInput.form\n if (hasSameFormOwner) {\n $exclusiveInput.checked = false\n this.syncConditionalRevealWithInputState($exclusiveInput)\n }\n })\n }\n\n /**\n * Click event handler\n *\n * Handle a click within the component root – if the click occurred on a checkbox,\n * sync the state of any associated conditional reveal with the checkbox\n * state.\n *\n * @private\n * @param {MouseEvent} event - Click event\n */\n handleClick(event) {\n const $clickedInput = event.target\n\n // Ignore clicks on things that aren't checkbox inputs\n if (\n !($clickedInput instanceof HTMLInputElement) ||\n $clickedInput.type !== 'checkbox'\n ) {\n return\n }\n\n // If the checkbox conditionally-reveals some content, sync the state\n const hasAriaControls = $clickedInput.getAttribute('aria-controls')\n if (hasAriaControls) {\n this.syncConditionalRevealWithInputState($clickedInput)\n }\n\n // No further behaviour needed for unchecking\n if (!$clickedInput.checked) {\n return\n }\n\n // Handle 'exclusive' checkbox behaviour (ie \"None of these\")\n const hasBehaviourExclusive =\n $clickedInput.getAttribute('data-behaviour') === 'exclusive'\n if (hasBehaviourExclusive) {\n this.unCheckAllInputsExcept($clickedInput)\n } else {\n this.unCheckExclusiveInputs($clickedInput)\n }\n }\n\n /**\n * Name for the component used when initialising using data-module attributes.\n */\n static moduleName = 'govuk-checkboxes'\n}\n"],"names":["isInitialised","$root","moduleName","HTMLElement","hasAttribute","isSupported","$scope","document","body","classList","contains","formatErrorMessage","Component","message","GOVUKFrontendError","Error","constructor","args","name","SupportError","supportMessage","HTMLScriptElement","prototype","ElementError","messageOrOptions","component","identifier","element","expectedType","InitError","componentOrMessage","GOVUKFrontendComponent","_$root","childConstructor","elementType","checkSupport","checkInitialised","setAttribute","Checkboxes","$inputs","querySelectorAll","length","forEach","$input","targetId","getAttribute","getElementById","removeAttribute","window","addEventListener","syncAllConditionalReveals","event","handleClick","syncConditionalRevealWithInputState","$target","inputIsChecked","checked","toString","toggle","unCheckAllInputsExcept","allInputsWithSameName","$inputWithSameName","hasSameFormOwner","form","unCheckExclusiveInputs","allInputsWithSameNameAndExclusiveBehaviour","$exclusiveInput","$clickedInput","target","HTMLInputElement","type","hasAriaControls","hasBehaviourExclusive"],"mappings":"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"}
1
+ {"version":3,"file":"checkboxes.bundle.mjs","sources":["../../../../src/govuk/common/index.mjs","../../../../src/govuk/errors/index.mjs","../../../../src/govuk/govuk-frontend-component.mjs","../../../../src/govuk/components/checkboxes/checkboxes.mjs"],"sourcesContent":["/**\n * Common helpers which do not require polyfill.\n *\n * IMPORTANT: If a helper require a polyfill, please isolate it in its own module\n * so that the polyfill can be properly tree-shaken and does not burden\n * the components that do not need that helper\n */\n\n/**\n * Get hash fragment from URL\n *\n * Extract the hash fragment (everything after the hash) from a URL,\n * but not including the hash symbol\n *\n * @private\n * @param {string} url - URL\n * @returns {string | undefined} Fragment from URL, without the hash\n */\nexport function getFragmentFromUrl(url) {\n if (!url.includes('#')) {\n return undefined\n }\n\n return url.split('#').pop()\n}\n\n/**\n * Get GOV.UK Frontend breakpoint value from CSS custom property\n *\n * @private\n * @param {string} name - Breakpoint name\n * @returns {{ property: string, value?: string }} Breakpoint object\n */\nexport function getBreakpoint(name) {\n const property = `--govuk-frontend-breakpoint-${name}`\n\n // Get value from `<html>` with breakpoints on CSS :root\n const value = window\n .getComputedStyle(document.documentElement)\n .getPropertyValue(property)\n\n return {\n property,\n value: value || undefined\n }\n}\n\n/**\n * Move focus to element\n *\n * Sets tabindex to -1 to make the element programmatically focusable,\n * but removes it on blur as the element doesn't need to be focused again.\n *\n * @private\n * @template {HTMLElement} FocusElement\n * @param {FocusElement} $element - HTML element\n * @param {object} [options] - Handler options\n * @param {function(this: FocusElement): void} [options.onBeforeFocus] - Callback before focus\n * @param {function(this: FocusElement): void} [options.onBlur] - Callback on blur\n */\nexport function setFocus($element, options = {}) {\n const isFocusable = $element.getAttribute('tabindex')\n\n if (!isFocusable) {\n $element.setAttribute('tabindex', '-1')\n }\n\n /**\n * Handle element focus\n */\n function onFocus() {\n $element.addEventListener('blur', onBlur, { once: true })\n }\n\n /**\n * Handle element blur\n */\n function onBlur() {\n options.onBlur?.call($element)\n\n if (!isFocusable) {\n $element.removeAttribute('tabindex')\n }\n }\n\n // Add listener to reset element on blur, after focus\n $element.addEventListener('focus', onFocus, { once: true })\n\n // Focus element\n options.onBeforeFocus?.call($element)\n $element.focus()\n}\n\n/**\n * Checks if component is already initialised\n *\n * @internal\n * @param {Element} $root - HTML element to be checked\n * @param {string} moduleName - name of component module\n * @returns {boolean} Whether component is already initialised\n */\nexport function isInitialised($root, moduleName) {\n return (\n $root instanceof HTMLElement &&\n $root.hasAttribute(`data-${moduleName}-init`)\n )\n}\n\n/**\n * Checks if GOV.UK Frontend is supported on this page\n *\n * Some browsers will load and run our JavaScript but GOV.UK Frontend\n * won't be supported.\n *\n * @param {HTMLElement | null} [$scope] - (internal) `<body>` HTML element checked for browser support\n * @returns {boolean} Whether GOV.UK Frontend is supported on this page\n */\nexport function isSupported($scope = document.body) {\n if (!$scope) {\n return false\n }\n\n return $scope.classList.contains('govuk-frontend-supported')\n}\n\n/**\n * Check for an array\n *\n * @internal\n * @param {unknown} option - Option to check\n * @returns {boolean} Whether the option is an array\n */\nfunction isArray(option) {\n return Array.isArray(option)\n}\n\n/**\n * Check for an object\n *\n * @internal\n * @param {unknown} option - Option to check\n * @returns {boolean} Whether the option is an object\n */\nexport function isObject(option) {\n return !!option && typeof option === 'object' && !isArray(option)\n}\n\n/**\n * Format error message\n *\n * @internal\n * @param {ComponentWithModuleName} Component - Component that threw the error\n * @param {string} message - Error message\n * @returns {string} - Formatted error message\n */\nexport function formatErrorMessage(Component, message) {\n return `${Component.moduleName}: ${message}`\n}\n\n/* eslint-disable jsdoc/valid-types --\n * `{new(...args: any[] ): object}` is not recognised as valid\n * https://github.com/gajus/eslint-plugin-jsdoc/issues/145#issuecomment-1308722878\n * https://github.com/jsdoc-type-pratt-parser/jsdoc-type-pratt-parser/issues/131\n **/\n\n/**\n * @typedef ComponentWithModuleName\n * @property {string} moduleName - Name of the component\n */\n\n/* eslint-enable jsdoc/valid-types */\n","import { formatErrorMessage } from '../common/index.mjs'\n\n/**\n * GOV.UK Frontend error\n *\n * A base class for `Error`s thrown by GOV.UK Frontend.\n *\n * It is meant to be extended into specific types of errors\n * to be thrown by our code.\n *\n * @example\n * ```js\n * class MissingRootError extends GOVUKFrontendError {\n * // Setting an explicit name is important as extending the class will not\n * // set a new `name` on the subclass. The `name` property is important\n * // to ensure intelligible error names even if the class name gets\n * // mangled by a minifier\n * name = \"MissingRootError\"\n * }\n * ```\n * @virtual\n */\nexport class GOVUKFrontendError extends Error {\n name = 'GOVUKFrontendError'\n}\n\n/**\n * Indicates that GOV.UK Frontend is not supported\n */\nexport class SupportError extends GOVUKFrontendError {\n name = 'SupportError'\n\n /**\n * Checks if GOV.UK Frontend is supported on this page\n *\n * @param {HTMLElement | null} [$scope] - HTML element `<body>` checked for browser support\n */\n constructor($scope = document.body) {\n const supportMessage =\n 'noModule' in HTMLScriptElement.prototype\n ? 'GOV.UK Frontend initialised without `<body class=\"govuk-frontend-supported\">` from template `<script>` snippet'\n : 'GOV.UK Frontend is not supported in this browser'\n\n super(\n $scope\n ? supportMessage\n : 'GOV.UK Frontend initialised without `<script type=\"module\">`'\n )\n }\n}\n\n/**\n * Indicates that a component has received an illegal configuration\n */\nexport class ConfigError extends GOVUKFrontendError {\n name = 'ConfigError'\n}\n\n/**\n * Indicates an issue with an element (possibly `null` or `undefined`)\n */\nexport class ElementError extends GOVUKFrontendError {\n name = 'ElementError'\n\n /**\n * @internal\n * @overload\n * @param {string} message - Element error message\n */\n\n /**\n * @internal\n * @overload\n * @param {ElementErrorOptions} options - Element error options\n */\n\n /**\n * @internal\n * @param {string | ElementErrorOptions} messageOrOptions - Element error message or options\n */\n constructor(messageOrOptions) {\n let message = typeof messageOrOptions === 'string' ? messageOrOptions : ''\n\n // Build message from options\n if (typeof messageOrOptions === 'object') {\n const { component, identifier, element, expectedType } = messageOrOptions\n\n message = identifier\n\n // Append reason\n message += element\n ? ` is not of type ${expectedType ?? 'HTMLElement'}`\n : ' not found'\n\n message = formatErrorMessage(component, message)\n }\n\n super(message)\n }\n}\n\n/**\n * Indicates that a component is already initialised\n */\nexport class InitError extends GOVUKFrontendError {\n name = 'InitError'\n\n /**\n * @internal\n * @param {ComponentWithModuleName | string} componentOrMessage - name of the component module\n */\n constructor(componentOrMessage) {\n const message =\n typeof componentOrMessage === 'string'\n ? componentOrMessage\n : formatErrorMessage(\n componentOrMessage,\n `Root element (\\`$root\\`) already initialised`\n )\n\n super(message)\n }\n}\n\n/**\n * Element error options\n *\n * @internal\n * @typedef {object} ElementErrorOptions\n * @property {string} identifier - An identifier that'll let the user understand which element has an error. This is whatever makes the most sense\n * @property {Element | null} [element] - The element in error\n * @property {string} [expectedType] - The type that was expected for the identifier\n * @property {ComponentWithModuleName} component - Component throwing the error\n */\n\n/**\n * @typedef {import('../common/index.mjs').ComponentWithModuleName} ComponentWithModuleName\n */\n","import { isInitialised, isSupported } from './common/index.mjs'\nimport { ElementError, InitError, SupportError } from './errors/index.mjs'\n\n/**\n * Base Component class\n *\n * Centralises the behaviours shared by our components\n *\n * @virtual\n * @template {Element} [RootElementType=HTMLElement]\n */\nexport class GOVUKFrontendComponent {\n /**\n * @type {typeof Element}\n */\n static elementType = HTMLElement\n\n // allows Typescript user to work around the lack of types\n // in GOVUKFrontend package, Typescript is not aware of $root\n // in components that extend GOVUKFrontendComponent\n /**\n * Returns the root element of the component\n *\n * @protected\n * @returns {RootElementType} - the root element of component\n */\n get $root() {\n return this._$root\n }\n\n /**\n * @protected\n * @type {RootElementType}\n */\n _$root\n\n /**\n * Constructs a new component, validating that GOV.UK Frontend is supported\n *\n * @internal\n * @param {Element | null} [$root] - HTML element to use for component\n */\n constructor($root) {\n const childConstructor = /** @type {ChildClassConstructor} */ (\n this.constructor\n )\n\n // TypeScript does not enforce that inheriting classes will define a `moduleName`\n // (even if we add a `@virtual` `static moduleName` property to this class).\n // While we trust users to do this correctly, we do a little check to provide them\n // a helpful error message.\n //\n // After this, we'll be sure that `childConstructor` has a `moduleName`\n // as expected of the `ChildClassConstructor` we've cast `this.constructor` to.\n if (typeof childConstructor.moduleName !== 'string') {\n throw new InitError(`\\`moduleName\\` not defined in component`)\n }\n\n if (!($root instanceof childConstructor.elementType)) {\n throw new ElementError({\n element: $root,\n component: childConstructor,\n identifier: 'Root element (`$root`)',\n expectedType: childConstructor.elementType.name\n })\n } else {\n this._$root = /** @type {RootElementType} */ ($root)\n }\n\n childConstructor.checkSupport()\n\n this.checkInitialised()\n\n const moduleName = childConstructor.moduleName\n\n this.$root.setAttribute(`data-${moduleName}-init`, '')\n }\n\n /**\n * Validates whether component is already initialised\n *\n * @private\n * @throws {InitError} when component is already initialised\n */\n checkInitialised() {\n const constructor = /** @type {ChildClassConstructor} */ (this.constructor)\n const moduleName = constructor.moduleName\n\n if (moduleName && isInitialised(this.$root, moduleName)) {\n throw new InitError(constructor)\n }\n }\n\n /**\n * Validates whether components are supported\n *\n * @throws {SupportError} when the components are not supported\n */\n static checkSupport() {\n if (!isSupported()) {\n throw new SupportError()\n }\n }\n}\n\n/**\n * @typedef ChildClass\n * @property {string} moduleName - The module name that'll be looked for in the DOM when initialising the component\n */\n\n/**\n * @typedef {typeof GOVUKFrontendComponent & ChildClass} ChildClassConstructor\n */\n","import { ElementError } from '../../errors/index.mjs'\nimport { GOVUKFrontendComponent } from '../../govuk-frontend-component.mjs'\n\n/**\n * Checkboxes component\n *\n * @preserve\n */\nexport class Checkboxes extends GOVUKFrontendComponent {\n /** @private */\n $inputs\n\n /**\n * Checkboxes can be associated with a 'conditionally revealed' content block\n * – for example, a checkbox for 'Phone' could reveal an additional form field\n * for the user to enter their phone number.\n *\n * These associations are made using a `data-aria-controls` attribute, which\n * is promoted to an aria-controls attribute during initialisation.\n *\n * We also need to restore the state of any conditional reveals on the page\n * (for example if the user has navigated back), and set up event handlers to\n * keep the reveal in sync with the checkbox state.\n *\n * @param {Element | null} $root - HTML element to use for checkboxes\n */\n constructor($root) {\n super($root)\n\n const $inputs = this.$root.querySelectorAll('input[type=\"checkbox\"]')\n if (!$inputs.length) {\n throw new ElementError({\n component: Checkboxes,\n identifier: 'Form inputs (`<input type=\"checkbox\">`)'\n })\n }\n\n this.$inputs = $inputs\n\n this.$inputs.forEach(($input) => {\n const targetId = $input.getAttribute('data-aria-controls')\n\n // Skip radios without data-aria-controls attributes\n if (!targetId) {\n return\n }\n\n // Throw if target conditional element does not exist.\n if (!document.getElementById(targetId)) {\n throw new ElementError({\n component: Checkboxes,\n identifier: `Conditional reveal (\\`id=\"${targetId}\"\\`)`\n })\n }\n\n // Promote the data-aria-controls attribute to a aria-controls attribute\n // so that the relationship is exposed in the AOM\n $input.setAttribute('aria-controls', targetId)\n $input.removeAttribute('data-aria-controls')\n })\n\n // When the page is restored after navigating 'back' in some browsers the\n // state of form controls is not restored until *after* the DOMContentLoaded\n // event is fired, so we need to sync after the pageshow event.\n window.addEventListener('pageshow', () => this.syncAllConditionalReveals())\n\n // Although we've set up handlers to sync state on the pageshow event, init\n // could be called after those events have fired, for example if they are\n // added to the page dynamically, so sync now too.\n this.syncAllConditionalReveals()\n\n // Handle events\n this.$root.addEventListener('click', (event) => this.handleClick(event))\n }\n\n /**\n * Sync the conditional reveal states for all checkboxes in this component.\n *\n * @private\n */\n syncAllConditionalReveals() {\n this.$inputs.forEach(($input) =>\n this.syncConditionalRevealWithInputState($input)\n )\n }\n\n /**\n * Sync conditional reveal with the input state\n *\n * Synchronise the visibility of the conditional reveal, and its accessible\n * state, with the input's checked state.\n *\n * @private\n * @param {HTMLInputElement} $input - Checkbox input\n */\n syncConditionalRevealWithInputState($input) {\n const targetId = $input.getAttribute('aria-controls')\n if (!targetId) {\n return\n }\n\n const $target = document.getElementById(targetId)\n if ($target?.classList.contains('govuk-checkboxes__conditional')) {\n const inputIsChecked = $input.checked\n\n $input.setAttribute('aria-expanded', inputIsChecked.toString())\n $target.classList.toggle(\n 'govuk-checkboxes__conditional--hidden',\n !inputIsChecked\n )\n }\n }\n\n /**\n * Uncheck other checkboxes\n *\n * Find any other checkbox inputs with the same name value, and uncheck them.\n * This is useful for when a “None of these\" checkbox is checked.\n *\n * @private\n * @param {HTMLInputElement} $input - Checkbox input\n */\n unCheckAllInputsExcept($input) {\n const allInputsWithSameName = document.querySelectorAll(\n `input[type=\"checkbox\"][name=\"${$input.name}\"]`\n )\n\n allInputsWithSameName.forEach(($inputWithSameName) => {\n const hasSameFormOwner = $input.form === $inputWithSameName.form\n if (hasSameFormOwner && $inputWithSameName !== $input) {\n $inputWithSameName.checked = false\n this.syncConditionalRevealWithInputState($inputWithSameName)\n }\n })\n }\n\n /**\n * Uncheck exclusive checkboxes\n *\n * Find any checkbox inputs with the same name value and the 'exclusive'\n * behaviour, and uncheck them. This helps prevent someone checking both a\n * regular checkbox and a \"None of these\" checkbox in the same fieldset.\n *\n * @private\n * @param {HTMLInputElement} $input - Checkbox input\n */\n unCheckExclusiveInputs($input) {\n const allInputsWithSameNameAndExclusiveBehaviour =\n document.querySelectorAll(\n `input[data-behaviour=\"exclusive\"][type=\"checkbox\"][name=\"${$input.name}\"]`\n )\n\n allInputsWithSameNameAndExclusiveBehaviour.forEach(($exclusiveInput) => {\n const hasSameFormOwner = $input.form === $exclusiveInput.form\n if (hasSameFormOwner) {\n $exclusiveInput.checked = false\n this.syncConditionalRevealWithInputState($exclusiveInput)\n }\n })\n }\n\n /**\n * Click event handler\n *\n * Handle a click within the component root – if the click occurred on a checkbox,\n * sync the state of any associated conditional reveal with the checkbox\n * state.\n *\n * @private\n * @param {MouseEvent} event - Click event\n */\n handleClick(event) {\n const $clickedInput = event.target\n\n // Ignore clicks on things that aren't checkbox inputs\n if (\n !($clickedInput instanceof HTMLInputElement) ||\n $clickedInput.type !== 'checkbox'\n ) {\n return\n }\n\n // If the checkbox conditionally-reveals some content, sync the state\n const hasAriaControls = $clickedInput.getAttribute('aria-controls')\n if (hasAriaControls) {\n this.syncConditionalRevealWithInputState($clickedInput)\n }\n\n // No further behaviour needed for unchecking\n if (!$clickedInput.checked) {\n return\n }\n\n // Handle 'exclusive' checkbox behaviour (ie \"None of these\")\n const hasBehaviourExclusive =\n $clickedInput.getAttribute('data-behaviour') === 'exclusive'\n if (hasBehaviourExclusive) {\n this.unCheckAllInputsExcept($clickedInput)\n } else {\n this.unCheckExclusiveInputs($clickedInput)\n }\n }\n\n /**\n * Name for the component used when initialising using data-module attributes.\n */\n static moduleName = 'govuk-checkboxes'\n}\n"],"names":["isInitialised","$root","moduleName","HTMLElement","hasAttribute","isSupported","$scope","document","body","classList","contains","formatErrorMessage","Component","message","GOVUKFrontendError","Error","constructor","args","name","SupportError","supportMessage","HTMLScriptElement","prototype","ElementError","messageOrOptions","component","identifier","element","expectedType","InitError","componentOrMessage","GOVUKFrontendComponent","_$root","childConstructor","elementType","checkSupport","checkInitialised","setAttribute","Checkboxes","$inputs","querySelectorAll","length","forEach","$input","targetId","getAttribute","getElementById","removeAttribute","window","addEventListener","syncAllConditionalReveals","event","handleClick","syncConditionalRevealWithInputState","$target","inputIsChecked","checked","toString","toggle","unCheckAllInputsExcept","allInputsWithSameName","$inputWithSameName","hasSameFormOwner","form","unCheckExclusiveInputs","allInputsWithSameNameAndExclusiveBehaviour","$exclusiveInput","$clickedInput","target","HTMLInputElement","type","hasAriaControls","hasBehaviourExclusive"],"mappings":"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"}
@@ -45,13 +45,13 @@
45
45
  "name": "autocomplete",
46
46
  "type": "string",
47
47
  "required": false,
48
- "description": "Attribute to [identify input purpose](https://www.w3.org/WAI/WCAG21/Understanding/identify-input-purpose.html), for instance `\"bday-day\"`. See [autofill](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill) for full list of attributes that can be used."
48
+ "description": "Attribute to meet [WCAG success criterion 1.3.5: Identify input purpose](https://www.w3.org/WAI/WCAG22/Understanding/identify-input-purpose.html), for instance `\"bday-day\"`. See the [Autofill section in the HTML standard](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill) section in the HTML standard for full list of attributes that can be used."
49
49
  },
50
50
  {
51
51
  "name": "pattern",
52
52
  "type": "string",
53
53
  "required": false,
54
- "description": "Attribute to [provide a regular expression pattern](https://html.spec.whatwg.org/multipage/sec-forms.html#the-pattern-attribute), used to match allowed character combinations for the input value."
54
+ "description": "Attribute to [provide a regular expression pattern](https://html.spec.whatwg.org/multipage/input.html#the-pattern-attribute), used to match allowed character combinations for the input value."
55
55
  },
56
56
  {
57
57
  "name": "classes",