Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 50 additions & 20 deletions docs/upgrade-to-6.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,20 @@ The updated [header](https://service-manual.nhs.uk/design-system/components/head

You can now use smaller versions of the [radios](https://service-manual.nhs.uk/design-system/components/radios) and [checkboxes](https://service-manual.nhs.uk/design-system/components/checkboxes) components by adding the `small` prop.

### Panel component
### Numbered pagination component

The [panel](https://service-manual.nhs.uk/design-system/components/panel) component from NHS.UK frontend v9.3.0 has been added:
The [pagination](https://service-manual.nhs.uk/design-system/components/notification-banner) component from NHS.UK frontend v10.1 has been updated to support numbered pagination:

```jsx
<Panel>
<Panel.Title>Booking complete</Panel.Title>
We have sent you a confirmation email
</Panel>
<Pagination>
<Pagination.Link href="/results?page=1" previous />
<Pagination.Item href="/results?page=1" number={1} />
<Pagination.Item href="/results?page=2" number={2} current />
<Pagination.Item href="/results?page=3" number={3} />
<Pagination.Link href="/results?page=3" next />
</Pagination>
```

This replaces the [list panel component](#list-panel) which was removed in NHS.UK frontend v6.0.0.

### Notification banner component

The [notification banner](https://service-manual.nhs.uk/design-system/components/notification-banner) component from NHS.UK frontend v10 has been added:
Expand All @@ -46,23 +47,32 @@ The [notification banner](https://service-manual.nhs.uk/design-system/components
</NotificationBanner>
```

### 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
<Panel>
<Panel.Title>Booking complete</Panel.Title>
We have sent you a confirmation email
</Panel>
```

This replaces the [list panel component](#list-panel) which was removed in NHS.UK frontend v6.0.0.

### Support for React Server Components (RSC)

All components have been tested as React Server Components (RSC) but due to [multipart namespace component limitations](https://ivicabatinic.from.hr/posts/multipart-namespace-components-addressing-rsc-and-dot-notation-issues) an alternative syntax (without dot notation) can be used as a workaround:

```patch
<Pagination>
- <Pagination.Link href="/section/treatments" previous>
+ <PaginationLink href="/section/treatments" previous>
Treatments
- </Pagination.Link>
+ </PaginationLink>
- <Pagination.Link href="/section/symptoms" next>
+ <PaginationLink href="/section/symptoms" next>
Symptoms
- </Pagination.Link>
+ </PaginationLink>
</Pagination>
<Breadcrumb>
- <Breadcrumb.Item href="#">Home</Breadcrumb.Item>
- <Breadcrumb.Item href="#">NHS services</Breadcrumb.Item>
- <Breadcrumb.Item href="#">Hospitals</Breadcrumb.Item>
+ <BreadcrumbItem href="#">Home</BreadcrumbItem>
+ <BreadcrumbItem href="#">NHS services</BreadcrumbItem>
+ <BreadcrumbItem href="#">Hospitals</BreadcrumbItem>
</Breadcrumb>
```

## Breaking changes
Expand Down Expand Up @@ -441,6 +451,26 @@ To align with NHS.UK frontend, the error summary component is automatically aler
</ErrorSummary>
```

### Pagination

To align with NHS.UK frontend, the pagination link component automatically renders its own "Previous page" or "Next page" text, with "page" being visually hidden. You will need to make the following changes:

- rename the `Pagination.Link` component to `Pagination.Item`
- move text content (or the `children` prop) to the `labelText` prop

```patch
<Pagination>
- <Pagination.Link href="/section/treatments" previous>
- Treatments
- </Pagination.Link>
- <Pagination.Link href="/section/symptoms" next>
- Symptoms
- </Pagination.Link>
+ <Pagination.Item labelText="Treatments" href="/section/treatments" previous />
+ <Pagination.Item labelText="Symptoms" href="/section/symptoms" next />
</Pagination>
```

### Select

You must rename the `Select` prop `selectRef` to `ref` for consistency with other components:
Expand Down
2 changes: 2 additions & 0 deletions src/__tests__/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,9 @@ describe('Index', () => {
'NotificationBannerLink',
'NotificationBannerTitle',
'Pagination',
'PaginationItem',
'PaginationLink',
'PaginationLinkText',
'Panel',
'PanelTitle',
'Radios',
Expand Down
85 changes: 38 additions & 47 deletions src/components/navigation/pagination/Pagination.tsx
Original file line number Diff line number Diff line change
@@ -1,63 +1,54 @@
import classNames from 'classnames';
import { forwardRef, type ComponentPropsWithoutRef } from 'react';
import { ArrowLeftIcon, ArrowRightIcon } from '#components/content-presentation/index.js';
import { type AsElementLink } from '#util/types/LinkTypes.js';
import { Children, forwardRef, type ComponentPropsWithoutRef } from 'react';
import { PaginationItem, PaginationLink } from './components/index.js';
import { childIsOfComponentType } from '#util/types/TypeGuards.js';

export interface PaginationLinkProps extends AsElementLink<HTMLAnchorElement> {
previous?: boolean;
next?: boolean;
}
export type PaginationProps = ComponentPropsWithoutRef<'nav'>;

const PaginationComponent = forwardRef<HTMLElement, PaginationProps>(
({ className, children, 'aria-label': ariaLabel = 'Pagination', ...rest }, forwardedRef) => {
const items = Children.toArray(children);

// Filter previous and next links
const links = items.filter((child) => childIsOfComponentType(child, PaginationLink));
const linkPrevious = links.find(({ props }) => props.previous);
const linkNext = links.find(({ props }) => props.next);

// Filter numbered list items
const listItems = items.filter((child) => childIsOfComponentType(child, PaginationItem));
const listItemsNumbered = listItems.filter(({ props }) => props.number || props.ellipsis);

export const PaginationLink = forwardRef<HTMLAnchorElement, PaginationLinkProps>(
({ className, children, asElement: Element = 'a', previous, next, ...rest }, forwardedRef) => (
<li
className={classNames(
{ 'nhsuk-pagination-item--previous': previous },
{ 'nhsuk-pagination-item--next': next },
)}
>
<Element
return (
<nav
className={classNames(
'nhsuk-pagination__link',
{ 'nhsuk-pagination__link--prev': previous },
{ 'nhsuk-pagination__link--next': next },
'nhsuk-pagination',
{ 'nhsuk-pagination--numbered': listItemsNumbered.length },
className,
)}
role="navigation"
aria-label={ariaLabel}
ref={forwardedRef}
{...rest}
>
<span className="nhsuk-pagination__title">
{previous ? 'Previous' : null}
{next ? 'Next' : null}
</span>
<span className="nhsuk-u-visually-hidden">:</span>
<span className="nhsuk-pagination__page">{children}</span>
{previous ? <ArrowLeftIcon /> : null}
{next ? <ArrowRightIcon /> : null}
</Element>
</li>
),
);

export type PaginationProps = ComponentPropsWithoutRef<'nav'>;

const PaginationComponent = forwardRef<HTMLElement, PaginationProps>(
({ className, children, 'aria-label': ariaLabel = 'Pagination', ...rest }, forwardedRef) => (
<nav
className={classNames('nhsuk-pagination', className)}
role="navigation"
aria-label={ariaLabel}
ref={forwardedRef}
{...rest}
>
<ul className="nhsuk-list nhsuk-pagination__list">{children}</ul>
</nav>
),
{linkPrevious}
<ul
className={
listItemsNumbered.length
? 'nhsuk-pagination__list' // Standard pagination list class
: 'nhsuk-list nhsuk-pagination__list' // Legacy pagination list class
}
>
{listItems}
</ul>
{linkNext}
</nav>
);
},
);

PaginationComponent.displayName = 'Pagination';
PaginationLink.displayName = 'Pagination.Link';

export const Pagination = Object.assign(PaginationComponent, {
Item: PaginationItem,
Link: PaginationLink,
});
Loading