diff --git a/packages/govuk-frontend/src/govuk/common/index.mjs b/packages/govuk-frontend/src/govuk/common/index.mjs index 8984b5a9e8..c3f21d11e2 100644 --- a/packages/govuk-frontend/src/govuk/common/index.mjs +++ b/packages/govuk-frontend/src/govuk/common/index.mjs @@ -133,6 +133,27 @@ export function getFragmentFromUrl(url) { return url.split('#').pop() } +/** + * Get GOV.UK Frontend breakpoint value from CSS custom property + * + * @private + * @param {string} name - Breakpoint name + * @returns {{ property: string, value?: string }} Breakpoint object + */ +export function getBreakpoint(name) { + const property = `--govuk-frontend-breakpoint-${name}` + + // Get value from `` with breakpoints on CSS :root + const value = window + .getComputedStyle(document.documentElement) + .getPropertyValue(property) + + return { + property, + value: value || undefined + } +} + /** * Move focus to element * diff --git a/packages/govuk-frontend/src/govuk/components/header/header.mjs b/packages/govuk-frontend/src/govuk/components/header/header.mjs index 856b7dff25..0e03a309b4 100644 --- a/packages/govuk-frontend/src/govuk/components/header/header.mjs +++ b/packages/govuk-frontend/src/govuk/components/header/header.mjs @@ -1,3 +1,4 @@ +import { getBreakpoint } from '../../common/index.mjs' import { ElementError } from '../../errors/index.mjs' import { GOVUKFrontendComponent } from '../../govuk-frontend-component.mjs' @@ -83,23 +84,42 @@ export class Header extends GOVUKFrontendComponent { this.$menu = $menu this.$menuButton = $menuButton - // Set the matchMedia to the govuk-frontend desktop breakpoint - this.mql = window.matchMedia('(min-width: 48.0625em)') + this.setupResponsiveChecks() + + this.$menuButton.addEventListener('click', () => + this.handleMenuButtonClick() + ) + } + + /** + * Setup viewport resize check + * + * @private + */ + setupResponsiveChecks() { + const breakpoint = getBreakpoint('desktop') + + if (!breakpoint.value) { + throw new ElementError({ + componentName: 'Header', + identifier: `CSS custom property (\`${breakpoint.property}\`) on pseudo-class \`:root\`` + }) + } + + // Media query list for GOV.UK Frontend desktop breakpoint + this.mql = window.matchMedia(`(min-width: ${breakpoint.value})`) // MediaQueryList.addEventListener isn't supported by Safari < 14 so we need // to be able to fall back to the deprecated MediaQueryList.addListener if ('addEventListener' in this.mql) { - this.mql.addEventListener('change', () => this.syncState()) + this.mql.addEventListener('change', () => this.checkMode()) } else { // @ts-expect-error Property 'addListener' does not exist // eslint-disable-next-line @typescript-eslint/no-unsafe-call - this.mql.addListener(() => this.syncState()) + this.mql.addListener(() => this.checkMode()) } - this.syncState() - this.$menuButton.addEventListener('click', () => - this.handleMenuButtonClick() - ) + this.checkMode() } /** @@ -112,7 +132,7 @@ export class Header extends GOVUKFrontendComponent { * * @private */ - syncState() { + checkMode() { if (!this.mql || !this.$menu || !this.$menuButton) { return } @@ -142,7 +162,7 @@ export class Header extends GOVUKFrontendComponent { */ handleMenuButtonClick() { this.menuIsOpen = !this.menuIsOpen - this.syncState() + this.checkMode() } /** diff --git a/packages/govuk-frontend/src/govuk/components/tabs/tabs.mjs b/packages/govuk-frontend/src/govuk/components/tabs/tabs.mjs index b5f79c381e..907c8a2e42 100644 --- a/packages/govuk-frontend/src/govuk/components/tabs/tabs.mjs +++ b/packages/govuk-frontend/src/govuk/components/tabs/tabs.mjs @@ -1,4 +1,4 @@ -import { getFragmentFromUrl } from '../../common/index.mjs' +import { getBreakpoint, getFragmentFromUrl } from '../../common/index.mjs' import { ElementError } from '../../errors/index.mjs' import { GOVUKFrontendComponent } from '../../govuk-frontend-component.mjs' @@ -105,7 +105,17 @@ export class Tabs extends GOVUKFrontendComponent { * @private */ setupResponsiveChecks() { - this.mql = window.matchMedia('(min-width: 40.0625em)') + const breakpoint = getBreakpoint('tablet') + + if (!breakpoint.value) { + throw new ElementError({ + componentName: 'Tabs', + identifier: `CSS custom property (\`${breakpoint.property}\`) on pseudo-class \`:root\`` + }) + } + + // Media query list for GOV.UK Frontend tablet breakpoint + this.mql = window.matchMedia(`(min-width: ${breakpoint.value})`) // MediaQueryList.addEventListener isn't supported by Safari < 14 so we need // to be able to fall back to the deprecated MediaQueryList.addListener diff --git a/packages/govuk-frontend/src/govuk/core/_all.scss b/packages/govuk-frontend/src/govuk/core/_all.scss index 3cc0d13c17..48e95beaf5 100644 --- a/packages/govuk-frontend/src/govuk/core/_all.scss +++ b/packages/govuk-frontend/src/govuk/core/_all.scss @@ -1,4 +1,4 @@ -@import "govuk-frontend-version"; +@import "govuk-frontend-properties"; @import "links"; @import "lists"; @import "typography"; diff --git a/packages/govuk-frontend/src/govuk/core/_govuk-frontend-version.scss b/packages/govuk-frontend/src/govuk/core/_govuk-frontend-properties.scss similarity index 51% rename from packages/govuk-frontend/src/govuk/core/_govuk-frontend-version.scss rename to packages/govuk-frontend/src/govuk/core/_govuk-frontend-properties.scss index 5e6d9a1645..0e211c4483 100644 --- a/packages/govuk-frontend/src/govuk/core/_govuk-frontend-version.scss +++ b/packages/govuk-frontend/src/govuk/core/_govuk-frontend-properties.scss @@ -2,4 +2,9 @@ // This variable is automatically overwritten during builds and releases. // It doesn't need to be updated manually. --govuk-frontend-version: "development"; + + // CSS custom property for each breakpoint + @each $name, $value in $govuk-breakpoints { + --govuk-frontend-breakpoint-#{$name}: #{govuk-px-to-rem($value)}; + } } diff --git a/packages/govuk-frontend/tasks/build/release.unit.test.mjs b/packages/govuk-frontend/tasks/build/release.unit.test.mjs index d72502f52d..dcc306660d 100644 --- a/packages/govuk-frontend/tasks/build/release.unit.test.mjs +++ b/packages/govuk-frontend/tasks/build/release.unit.test.mjs @@ -49,8 +49,18 @@ describe('dist/', () => { ) }) - it('should contain version number custom property', () => { + it('should contain CSS custom properties', () => { + // GOV.UK Frontend version number expect(stylesheet).toContain(`--govuk-frontend-version:"${pkg.version}"`) + + // Breakpoints for `window.matchMedia()` in Header, Tabs components + expect(stylesheet).toContain('--govuk-frontend-breakpoint-mobile:20rem') + expect(stylesheet).toContain( + '--govuk-frontend-breakpoint-tablet:40.0625rem' + ) + expect(stylesheet).toContain( + '--govuk-frontend-breakpoint-desktop:48.0625rem' + ) }) }) @@ -70,7 +80,7 @@ describe('dist/', () => { '../packages/govuk-frontend/src/govuk/all.scss' ) expect(sourcemap.sources).toContain( - '../packages/govuk-frontend/src/govuk/core/_govuk-frontend-version.scss' + '../packages/govuk-frontend/src/govuk/core/_govuk-frontend-properties.scss' ) }) })