govuk-frontend
Version:
GOV.UK Frontend contains the code you need to start building a user interface for government platforms and services.
1 lines • 8.48 kB
Source Map (JSON)
{"version":3,"file":"radios.mjs","sources":["../../../../src/govuk/components/radios/radios.mjs"],"sourcesContent":["import { ElementError } from '../../errors/index.mjs'\nimport { GOVUKFrontendComponent } from '../../govuk-frontend-component.mjs'\n\n/**\n * Radios component\n *\n * @preserve\n */\nexport class Radios extends GOVUKFrontendComponent {\n /** @private */\n $inputs\n\n /**\n * Radios can be associated with a 'conditionally revealed' content block –\n * for example, a radio for 'Phone' could reveal an additional form field for\n * 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 radio state.\n *\n * @param {Element | null} $root - HTML element to use for radios\n */\n constructor($root) {\n super($root)\n\n const $inputs = this.$root.querySelectorAll('input[type=\"radio\"]')\n if (!$inputs.length) {\n throw new ElementError({\n component: Radios,\n identifier: 'Form inputs (`<input type=\"radio\">`)'\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: Radios,\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 radio buttons 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 - Radio 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-radios__conditional')) {\n const inputIsChecked = $input.checked\n\n $input.setAttribute('aria-expanded', inputIsChecked.toString())\n $target.classList.toggle(\n 'govuk-radios__conditional--hidden',\n !inputIsChecked\n )\n }\n }\n\n /**\n * Click event handler\n *\n * Handle a click within the component root – if the click occurred on a radio, sync\n * the state of the conditional reveal for all radio buttons in the same form\n * with the same name (because checking one radio could have un-checked a\n * radio under the root of another Radio component)\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 radio buttons\n if (\n !($clickedInput instanceof HTMLInputElement) ||\n $clickedInput.type !== 'radio'\n ) {\n return\n }\n\n // We only need to consider radios with conditional reveals, which will have\n // aria-controls attributes.\n const $allInputs = document.querySelectorAll(\n 'input[type=\"radio\"][aria-controls]'\n )\n\n const $clickedInputForm = $clickedInput.form\n const $clickedInputName = $clickedInput.name\n\n $allInputs.forEach(($input) => {\n const hasSameFormOwner = $input.form === $clickedInputForm\n const hasSameName = $input.name === $clickedInputName\n\n if (hasSameName && hasSameFormOwner) {\n this.syncConditionalRevealWithInputState($input)\n }\n })\n }\n\n /**\n * Name for the component used when initialising using data-module attributes.\n */\n static moduleName = 'govuk-radios'\n}\n"],"names":["Radios","GOVUKFrontendComponent","constructor","$root","$inputs","querySelectorAll","length","ElementError","component","identifier","forEach","$input","targetId","getAttribute","document","getElementById","setAttribute","removeAttribute","window","addEventListener","syncAllConditionalReveals","event","handleClick","syncConditionalRevealWithInputState","$target","classList","contains","inputIsChecked","checked","toString","toggle","$clickedInput","target","HTMLInputElement","type","$allInputs","$clickedInputForm","form","$clickedInputName","name","hasSameFormOwner","hasSameName","moduleName"],"mappings":"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"}