From a79f9103300727c16ffa75a844a24d4a98e46546 Mon Sep 17 00:00:00 2001 From: Colin Rotherham Date: Tue, 7 Oct 2025 15:15:03 +0100 Subject: [PATCH 1/4] Update changelog for previous fixes --- docs/upgrade-to-6.0.md | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/docs/upgrade-to-6.0.md b/docs/upgrade-to-6.0.md index b16402fff..b00a65057 100644 --- a/docs/upgrade-to-6.0.md +++ b/docs/upgrade-to-6.0.md @@ -6,6 +6,18 @@ There are some breaking changes you'll need to be aware of when upgrading to v6. You must read and apply these updates carefully to make sure your service does not break. +## New features + +### New header component with account section + +The updated [header](https://service-manual.nhs.uk/design-system/components/header) component from NHS.UK frontend v10.x has been added, including support for account information and links. As part of this work we’ve also made some other improvements to the header: + +- show currently active section or page in the navigation +- align navigation items to the left by default +- update navigation label from ’Primary navigation’ to ‘Menu’, and remove superfluous `role` and `id` attributes +- update NHS logo in the header to have higher contrast when focused +- refactor CSS classes and BEM naming, use hidden attributes instead of modifier classes, use generic search element + ## Breaking changes ### Update the JavaScript supported script snippet @@ -210,7 +222,7 @@ To align with NHS.UK frontend, the date input component automatically renders it The custom `autoSelectNext` prop is no longer supported. -### New header component with account section +### Header The updated header component from NHS.UK frontend v10.x has been added. You will need to make the following changes: @@ -464,3 +476,22 @@ To align with NHS.UK frontend, the warning callout `WarningCallout.Label` compon

``` + +## Fixes + +- [#52: Expose header navigation open/close state (with setter)](https://github.com/NHSDigital/nhsuk-react-components/issues/52) +- [#69: Unable to use ref attribute on some components](https://github.com/NHSDigital/nhsuk-react-components/issues/69) +- [#71: Expose FormGroup component to consumers](https://github.com/NHSDigital/nhsuk-react-components/issues/71) +- [#105: getHeadingsFromChildren forces use of string as table cell child](https://github.com/NHSDigital/nhsuk-react-components/issues/105) +- [#166: SkipLink double jumps to first heading then #maincontent if disableDefaultBehaviour is not set](https://github.com/NHSDigital/nhsuk-react-components/issues/166) +- [#174: Responsive tables and validation errors](https://github.com/NHSDigital/nhsuk-react-components/issues/174) +- [#214: Hints and errors are not semantically associated with fieldsets](https://github.com/NHSDigital/nhsuk-react-components/issues/214) +- [#215: Suggestion: remove all 'boolean' examples from storybook](https://github.com/NHSDigital/nhsuk-react-components/issues/215) +- [#243: Use correct NHS.UK frontend JavaScript when rendered client-side](https://github.com/NHSDigital/nhsuk-react-components/issues/243) +- [#244: Breaking change: remove default legend and label sizes or else change to l](https://github.com/NHSDigital/nhsuk-react-components/issues/244) +- [#245: Fieldset incorrectly gets set in error when a child input is in error](https://github.com/NHSDigital/nhsuk-react-components/issues/245) +- [#247: Date component uses label rather than fieldset with legend](https://github.com/NHSDigital/nhsuk-react-components/issues/247) +- [#256: SkipLink does not work if intended target header is rerendered](https://github.com/NHSDigital/nhsuk-react-components/issues/256) +- [#259: Remove pattern="[0-9]\*" from date inputs](https://github.com/NHSDigital/nhsuk-react-components/issues/259) +- [#260: Allow custom component for button links](https://github.com/NHSDigital/nhsuk-react-components/issues/260) +- [#265: Header logo is not labeled correctly when organisation info is provided](https://github.com/NHSDigital/nhsuk-react-components/issues/265) From 222b10a7259a9900e0e8418d3d29a7466da26107 Mon Sep 17 00:00:00 2001 From: Colin Rotherham Date: Tue, 7 Oct 2025 17:34:16 +0100 Subject: [PATCH 2/4] Add panel component --- src/__tests__/index.test.ts | 1 + src/components/content-presentation/index.ts | 1 + .../content-presentation/panel/Panel.tsx | 36 +++++++++ .../panel/__tests__/Panel.test.tsx | 74 +++++++++++++++++++ .../__snapshots__/Panel.test.tsx.snap | 58 +++++++++++++++ .../content-presentation/panel/index.ts | 1 + .../Content Presentation/Panel.stories.tsx | 27 +++++++ 7 files changed, 198 insertions(+) create mode 100644 src/components/content-presentation/panel/Panel.tsx create mode 100644 src/components/content-presentation/panel/__tests__/Panel.test.tsx create mode 100644 src/components/content-presentation/panel/__tests__/__snapshots__/Panel.test.tsx.snap create mode 100644 src/components/content-presentation/panel/index.ts create mode 100644 stories/Content Presentation/Panel.stories.tsx diff --git a/src/__tests__/index.test.ts b/src/__tests__/index.test.ts index 1e30bc1fa..f20617293 100644 --- a/src/__tests__/index.test.ts +++ b/src/__tests__/index.test.ts @@ -52,6 +52,7 @@ describe('Index', () => { 'Legend', 'NavAZ', 'Pagination', + 'Panel', 'Radios', 'RadiosContext', 'ReadingWidth', diff --git a/src/components/content-presentation/index.ts b/src/components/content-presentation/index.ts index 973fd2744..55a38c078 100644 --- a/src/components/content-presentation/index.ts +++ b/src/components/content-presentation/index.ts @@ -4,6 +4,7 @@ export * from './hero/index.js'; export * from './icons/index.js'; export * from './images/index.js'; export * from './inset-text/index.js'; +export * from './panel/index.js'; export * from './summary-list/index.js'; export * from './table/index.js'; export * from './tabs/index.js'; diff --git a/src/components/content-presentation/panel/Panel.tsx b/src/components/content-presentation/panel/Panel.tsx new file mode 100644 index 000000000..ce2d1f352 --- /dev/null +++ b/src/components/content-presentation/panel/Panel.tsx @@ -0,0 +1,36 @@ +import classNames from 'classnames'; +import { Children, forwardRef, type ComponentPropsWithoutRef, type FC } from 'react'; +import { HeadingLevel, type HeadingLevelProps } from '#components/utils/HeadingLevel.js'; +import { childIsOfComponentType } from '#util/types/TypeGuards.js'; + +export type PanelTitleProps = HeadingLevelProps; + +const PanelTitle: FC = ({ children, headingLevel = 'h1', ...rest }) => ( + + {children} + +); + +export type PanelProps = ComponentPropsWithoutRef<'div'>; + +const PanelComponent = forwardRef( + ({ children, className, ...rest }, forwardedRef) => { + const items = Children.toArray(children); + const title = items.find((child) => childIsOfComponentType(child, PanelTitle)); + const bodyItems = items.filter((child) => !childIsOfComponentType(child, PanelTitle)); + + return ( +
+ {title} + {bodyItems ?
{bodyItems}
: null} +
+ ); + }, +); + +PanelComponent.displayName = 'Panel'; +PanelComponent.displayName = 'Panel.Title'; + +export const Panel = Object.assign(PanelComponent, { + Title: PanelTitle, +}); diff --git a/src/components/content-presentation/panel/__tests__/Panel.test.tsx b/src/components/content-presentation/panel/__tests__/Panel.test.tsx new file mode 100644 index 000000000..1cfde1a6e --- /dev/null +++ b/src/components/content-presentation/panel/__tests__/Panel.test.tsx @@ -0,0 +1,74 @@ +import { render } from '@testing-library/react'; +import { createRef } from 'react'; +import { Panel, type PanelTitleProps } from '..'; +import { renderClient, renderServer } from '#util/components'; + +describe('Panel', () => { + it('matches snapshot', async () => { + const { container } = await renderClient( + + Booking complete + We have sent you a confirmation email + , + { className: 'nhsuk-panel' }, + ); + + expect(container).toMatchSnapshot(); + }); + + it('matches snapshot (via server)', async () => { + const { container, element } = await renderServer( + + Booking complete + We have sent you a confirmation email + , + { className: 'nhsuk-panel' }, + ); + + expect(container).toMatchSnapshot('server'); + + await renderClient(element, { + className: 'nhsuk-panel', + hydrate: true, + container, + }); + + expect(container).toMatchSnapshot('client'); + }); + + it('forwards refs', async () => { + const ref = createRef(); + + const { modules } = await renderClient( + + Booking complete + We have sent you a confirmation email + , + { className: 'nhsuk-panel' }, + ); + + const [panelEl] = modules; + + expect(ref.current).toBe(panelEl); + expect(ref.current).toHaveClass('nhsuk-panel'); + }); + + it.each([ + undefined, + { headingLevel: 'h1' }, + { headingLevel: 'h2' }, + { headingLevel: 'h3' }, + { headingLevel: 'h4' }, + ])('renders heading level $headingLevel if specified', (props) => { + const { container } = render( + + Booking complete + We have sent you a confirmation email + , + ); + + const title = container.querySelector('.nhsuk-panel__title'); + + expect(title).toHaveProperty('tagName', props?.headingLevel?.toUpperCase() ?? 'H1'); + }); +}); diff --git a/src/components/content-presentation/panel/__tests__/__snapshots__/Panel.test.tsx.snap b/src/components/content-presentation/panel/__tests__/__snapshots__/Panel.test.tsx.snap new file mode 100644 index 000000000..a2ae20ed3 --- /dev/null +++ b/src/components/content-presentation/panel/__tests__/__snapshots__/Panel.test.tsx.snap @@ -0,0 +1,58 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`Panel matches snapshot (via server): client 1`] = ` +
+
+

+ Booking complete +

+
+ We have sent you a confirmation email +
+
+
+`; + +exports[`Panel matches snapshot (via server): server 1`] = ` +
+
+

+ Booking complete +

+
+ We have sent you a confirmation email +
+
+
+`; + +exports[`Panel matches snapshot 1`] = ` +
+
+

+ Booking complete +

+
+ We have sent you a confirmation email +
+
+
+`; diff --git a/src/components/content-presentation/panel/index.ts b/src/components/content-presentation/panel/index.ts new file mode 100644 index 000000000..81c82d413 --- /dev/null +++ b/src/components/content-presentation/panel/index.ts @@ -0,0 +1 @@ +export * from './Panel.js'; diff --git a/stories/Content Presentation/Panel.stories.tsx b/stories/Content Presentation/Panel.stories.tsx new file mode 100644 index 000000000..d8f289cd7 --- /dev/null +++ b/stories/Content Presentation/Panel.stories.tsx @@ -0,0 +1,27 @@ +import { type Meta, type StoryObj } from '@storybook/react-vite'; +import { Panel } from '#components'; + +const meta: Meta = { + title: 'Content Presentation/Panel', + component: Panel, +}; +export default meta; +type Story = StoryObj; + +export const StandardPanel: Story = { + render: () => ( + + Booking complete + We have sent you a confirmation email + + ), +}; + +export const PanelWithCustomHeadingLevel: Story = { + render: () => ( + + Booking complete + We have sent you a confirmation email + + ), +}; From 7fa86048c2c81d1b54826079f00fa492cb7c8cbd Mon Sep 17 00:00:00 2001 From: Colin Rotherham Date: Tue, 7 Oct 2025 16:50:13 +0100 Subject: [PATCH 3/4] Add changelog entry --- CHANGELOG.md | 6 ++++++ docs/upgrade-to-6.0.md | 13 +++++++++++++ 2 files changed, 19 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5141e92b8..d4971eddd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # NHS.UK React components +## Unreleased + +This version adds the panel component from NHS.UK frontend v9.3.0 and supports React v19. + +For a full list of changes in this release please refer to the [migration doc](https://github.com/NHSDigital/nhsuk-react-components/blob/main/docs/upgrade-to-6.0.md). + ## 6.0.0-beta.0 - 30 September 2025 This version provides support for nhsuk-frontend version 10. diff --git a/docs/upgrade-to-6.0.md b/docs/upgrade-to-6.0.md index b00a65057..8c09dc05b 100644 --- a/docs/upgrade-to-6.0.md +++ b/docs/upgrade-to-6.0.md @@ -18,6 +18,19 @@ The updated [header](https://service-manual.nhs.uk/design-system/components/head - update NHS logo in the header to have higher contrast when focused - refactor CSS classes and BEM naming, use hidden attributes instead of modifier classes, use generic search element +### Panel component + +The [panel](https://service-manual.nhs.uk/design-system/components/panel) component from NHS.UK frontend v9.3.0 has been added: + +```jsx + + Booking complete + We have sent you a confirmation email + +``` + +This replaces the [list panel component](#list-panel) which was removed in NHS.UK frontend v6.0.0. + ## Breaking changes ### Update the JavaScript supported script snippet From dbb64bee83ed21da64de18232b276d3bcc413adf Mon Sep 17 00:00:00 2001 From: Colin Rotherham Date: Tue, 7 Oct 2025 16:52:48 +0100 Subject: [PATCH 4/4] Update package version to v6.0.0-beta.1 --- CHANGELOG.md | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d4971eddd..9c08600f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # NHS.UK React components -## Unreleased +## 6.0.0-beta.1 - 8 October 2025 This version adds the panel component from NHS.UK frontend v9.3.0 and supports React v19. diff --git a/package.json b/package.json index 439fe4e1a..d0cc1bd23 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nhsuk-react-components", - "version": "6.0.0-beta.0", + "version": "6.0.0-beta.1", "license": "MIT", "author": { "name": "NHS England"