UNPKG

govuk-frontend

Version:

GOV.UK Frontend contains the code you need to start building a user interface for government platforms and services.

1 lines 9.34 kB
{"version":3,"file":"service-navigation.mjs","sources":["../../../../src/govuk/components/service-navigation/service-navigation.mjs"],"sourcesContent":["import { getBreakpoint } from '../../common/index.mjs'\nimport { Component } from '../../component.mjs'\nimport { ElementError } from '../../errors/index.mjs'\n\n/**\n * Service Navigation component\n *\n * @preserve\n */\nexport class ServiceNavigation extends Component {\n /** @private */\n $menuButton\n\n /** @private */\n $menu\n\n /**\n * Remember the open/closed state of the nav so we can maintain it when the\n * screen is resized.\n *\n * @private\n */\n menuIsOpen = false\n\n /**\n * A global const for storing a matchMedia instance which we'll use to detect\n * when a screen size change happens. We rely on it being null if the feature\n * isn't available to initially apply hidden attributes\n *\n * @private\n * @type {MediaQueryList | null}\n */\n mql = null\n\n /**\n * @param {Element | null} $root - HTML element to use for header\n */\n constructor($root) {\n super($root)\n\n const $menuButton = this.$root.querySelector(\n '.govuk-js-service-navigation-toggle'\n )\n\n // Headers don't necessarily have a navigation. When they don't, the menu\n // toggle won't be rendered by our macro (or may be omitted when writing\n // plain HTML)\n if (!$menuButton) {\n return this\n }\n\n const menuId = $menuButton.getAttribute('aria-controls')\n if (!menuId) {\n throw new ElementError({\n component: ServiceNavigation,\n identifier:\n 'Navigation button (`<button class=\"govuk-js-service-navigation-toggle\">`) attribute (`aria-controls`)'\n })\n }\n\n const $menu = document.getElementById(menuId)\n if (!$menu) {\n throw new ElementError({\n component: ServiceNavigation,\n element: $menu,\n identifier: `Navigation (\\`<ul id=\"${menuId}\">\\`)`\n })\n }\n\n this.$menu = $menu\n this.$menuButton = $menuButton\n\n this.setupResponsiveChecks()\n\n this.$menuButton.addEventListener('click', () =>\n this.handleMenuButtonClick()\n )\n }\n\n /**\n * Setup viewport resize check\n *\n * @private\n */\n setupResponsiveChecks() {\n const breakpoint = getBreakpoint('tablet')\n\n if (!breakpoint.value) {\n throw new ElementError({\n component: ServiceNavigation,\n identifier: `CSS custom property (\\`${breakpoint.property}\\`) on pseudo-class \\`:root\\``\n })\n }\n\n // Media query list for GOV.UK Frontend desktop breakpoint\n this.mql = window.matchMedia(`(min-width: ${breakpoint.value})`)\n\n // MediaQueryList.addEventListener isn't supported by Safari < 14 so we need\n // to be able to fall back to the deprecated MediaQueryList.addListener\n if ('addEventListener' in this.mql) {\n this.mql.addEventListener('change', () => this.checkMode())\n } else {\n // @ts-expect-error Property 'addListener' does not exist\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call\n this.mql.addListener(() => this.checkMode())\n }\n\n this.checkMode()\n }\n\n /**\n * Sync menu state\n *\n * Uses the global variable menuIsOpen to correctly set the accessible and\n * visual states of the menu and the menu button.\n * Additionally will force the menu to be visible and the menu button to be\n * hidden if the matchMedia is triggered to desktop.\n *\n * @private\n */\n checkMode() {\n if (!this.mql || !this.$menu || !this.$menuButton) {\n return\n }\n\n if (this.mql.matches) {\n this.$menu.removeAttribute('hidden')\n setAttributes(this.$menuButton, attributesForHidingButton)\n } else {\n removeAttributes(this.$menuButton, Object.keys(attributesForHidingButton))\n this.$menuButton.setAttribute('aria-expanded', this.menuIsOpen.toString())\n\n if (this.menuIsOpen) {\n this.$menu.removeAttribute('hidden')\n } else {\n this.$menu.setAttribute('hidden', '')\n }\n }\n }\n\n /**\n * Handle menu button click\n *\n * When the menu button is clicked, change the visibility of the menu and then\n * sync the accessibility state and menu button state\n *\n * @private\n */\n handleMenuButtonClick() {\n this.menuIsOpen = !this.menuIsOpen\n this.checkMode()\n }\n\n /**\n * Name for the component used when initialising using data-module attributes.\n */\n static moduleName = 'govuk-service-navigation'\n}\n\n/**\n * Collection of attributes that needs setting on a `<button>`\n * to fully hide it, both visually and from screen-readers,\n * and prevent its activation while hidden\n */\nconst attributesForHidingButton = {\n hidden: '',\n // Fix button still appearing in VoiceOver's form control's menu despite being hidden\n // https://bugs.webkit.org/show_bug.cgi?id=300899\n 'aria-hidden': 'true'\n}\n\n/**\n * Sets a group of attributes on the given element\n *\n * @param {Element} $element - The element to set the attribute on\n * @param {{[attributeName: string]: string}} attributes - The attributes to set\n */\nfunction setAttributes($element, attributes) {\n for (const attributeName in attributes) {\n $element.setAttribute(attributeName, attributes[attributeName])\n }\n}\n\n/**\n * Removes a list of attributes from the given element\n *\n * @param {Element} $element - The element to remove the attributes from\n * @param {string[]} attributeNames - The names of the attributes to remove\n */\nfunction removeAttributes($element, attributeNames) {\n for (const attributeName of attributeNames) {\n $element.removeAttribute(attributeName)\n }\n}\n"],"names":["ServiceNavigation","Component","constructor","$root","$menuButton","$menu","menuIsOpen","mql","querySelector","menuId","getAttribute","ElementError","component","identifier","document","getElementById","element","setupResponsiveChecks","addEventListener","handleMenuButtonClick","breakpoint","getBreakpoint","value","property","window","matchMedia","checkMode","addListener","matches","removeAttribute","setAttributes","attributesForHidingButton","removeAttributes","Object","keys","setAttribute","toString","moduleName","hidden","$element","attributes","attributeName","attributeNames"],"mappings":"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"}