@i-dot-ai-npm/component-library-react 0.0.3 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/breadcrumbs/BreadcrumbItem.tsx +8 -0
- package/src/character-count/CharacterCount.tsx +5 -2
- package/src/date-input/DateInputField.tsx +2 -2
- package/src/error-summary/ErrorSummaryItem.tsx +6 -3
- package/src/exit-this-page/ExitThisPage.tsx +40 -0
- package/src/feedback/Feedback.tsx +27 -0
- package/src/fieldset/FieldsetLegend.tsx +5 -2
- package/src/footer/Footer.tsx +203 -0
- package/src/govuk-header/GovukHeader.tsx +61 -0
- package/src/header/Header.tsx +4 -2
- package/src/index.ts +18 -0
- package/src/label/Label.tsx +31 -0
- package/src/language-navigation/LanguageNavigation.tsx +27 -0
- package/src/language-navigation/LanguageNavigationItem.tsx +56 -0
- package/src/pagination/PaginationItem.tsx +25 -12
- package/src/pagination/PaginationNext.tsx +31 -9
- package/src/pagination/PaginationPrev.tsx +30 -9
- package/src/panel/Panel.tsx +24 -0
- package/src/panel/PanelActions.tsx +17 -0
- package/src/panel/PanelBody.tsx +17 -0
- package/src/panel/PanelTitle.tsx +17 -0
- package/src/phase-banner/PhaseBanner.tsx +1 -1
- package/src/phase-banner/PhaseBannerText.tsx +17 -0
- package/src/service-navigation/ServiceNavigation.tsx +84 -8
- package/src/service-navigation/ServiceNavigationItem.tsx +28 -6
- package/src/summary-card/SummaryCard.tsx +17 -0
- package/src/summary-card/SummaryCardAction.tsx +17 -0
- package/src/summary-card/SummaryCardActions.tsx +28 -0
- package/src/summary-card/SummaryCardContent.tsx +17 -0
- package/src/summary-card/SummaryCardTitle.tsx +17 -0
- package/src/summary-card/SummaryCardTitleWrapper.tsx +17 -0
- package/src/table/TableHeader.tsx +3 -2
package/package.json
CHANGED
|
@@ -10,6 +10,14 @@ type BreadcrumbItemProps = {
|
|
|
10
10
|
export default function BreadcrumbItem({ href, class: className, children, ...rest }: BreadcrumbItemProps) {
|
|
11
11
|
const classes = ["govuk-breadcrumbs__list-item", className ?? ""].filter(Boolean).join(" ");
|
|
12
12
|
|
|
13
|
+
if (href === undefined) {
|
|
14
|
+
return (
|
|
15
|
+
<li className={classes} aria-current="page" {...rest}>
|
|
16
|
+
{children ?? ""}
|
|
17
|
+
</li>
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
13
21
|
return (
|
|
14
22
|
<li className={classes} {...rest}>
|
|
15
23
|
<a className="govuk-breadcrumbs__link" href={href}>
|
|
@@ -1,12 +1,15 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
|
|
1
3
|
type CharacterCountProps = {
|
|
2
4
|
class?: string;
|
|
5
|
+
children?: ReactNode;
|
|
3
6
|
[key: string]: unknown;
|
|
4
7
|
};
|
|
5
8
|
|
|
6
|
-
export default function CharacterCount({ class: className, ...rest }: CharacterCountProps) {
|
|
9
|
+
export default function CharacterCount({ class: className, children, ...rest }: CharacterCountProps) {
|
|
7
10
|
const classes = ["govuk-textarea govuk-js-character-count", className ?? ""].filter(Boolean).join(" ");
|
|
8
11
|
|
|
9
12
|
return (
|
|
10
|
-
<textarea className={classes} {...rest}
|
|
13
|
+
<textarea className={classes} {...rest}>{children ?? ""}</textarea>
|
|
11
14
|
);
|
|
12
15
|
}
|
|
@@ -4,10 +4,10 @@ type DateInputFieldProps = {
|
|
|
4
4
|
[key: string]: unknown;
|
|
5
5
|
};
|
|
6
6
|
|
|
7
|
-
export default function DateInputField({ width
|
|
7
|
+
export default function DateInputField({ width, class: className, ...rest }: DateInputFieldProps) {
|
|
8
8
|
const classes = [
|
|
9
9
|
"govuk-input govuk-date-input__input",
|
|
10
|
-
({ "2": "govuk-input--width-2", "3": "govuk-input--width-3", "4": "govuk-input--width-4" }[width] ?? ""),
|
|
10
|
+
({ "2": "govuk-input--width-2", "3": "govuk-input--width-3", "4": "govuk-input--width-4" }[width ?? ""] ?? ""),
|
|
11
11
|
className ?? "",
|
|
12
12
|
]
|
|
13
13
|
.filter(Boolean)
|
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
2
|
|
|
3
3
|
type ErrorSummaryItemProps = {
|
|
4
|
+
href?: string;
|
|
4
5
|
class?: string;
|
|
5
6
|
children?: ReactNode;
|
|
6
7
|
[key: string]: unknown;
|
|
7
8
|
};
|
|
8
9
|
|
|
9
|
-
export default function ErrorSummaryItem({ class: className, children, ...rest }: ErrorSummaryItemProps) {
|
|
10
|
-
|
|
10
|
+
export default function ErrorSummaryItem({ href, class: className, children, ...rest }: ErrorSummaryItemProps) {
|
|
11
|
+
if (href === undefined) {
|
|
12
|
+
return <li>{children ?? ""}</li>;
|
|
13
|
+
}
|
|
11
14
|
|
|
12
15
|
return (
|
|
13
16
|
<li>
|
|
14
|
-
<a className={
|
|
17
|
+
<a href={href} className={className} {...rest}>
|
|
15
18
|
{children ?? ""}
|
|
16
19
|
</a>
|
|
17
20
|
</li>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
type ExitThisPageProps = {
|
|
4
|
+
redirectUrl?: string;
|
|
5
|
+
id?: string;
|
|
6
|
+
class?: string;
|
|
7
|
+
children?: ReactNode;
|
|
8
|
+
[key: string]: unknown;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export default function ExitThisPage({
|
|
12
|
+
redirectUrl = 'https://www.bbc.co.uk/weather',
|
|
13
|
+
id,
|
|
14
|
+
class: className,
|
|
15
|
+
children,
|
|
16
|
+
...rest
|
|
17
|
+
}: ExitThisPageProps) {
|
|
18
|
+
const classes = ['govuk-exit-this-page', className ?? ''].filter(Boolean).join(' ');
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<div id={id} className={classes} data-module="govuk-exit-this-page" {...rest}>
|
|
22
|
+
<a
|
|
23
|
+
href={redirectUrl}
|
|
24
|
+
role="button"
|
|
25
|
+
draggable="false"
|
|
26
|
+
className="govuk-button govuk-button--warning govuk-exit-this-page__button govuk-js-exit-this-page-button"
|
|
27
|
+
data-module="govuk-button"
|
|
28
|
+
rel="nofollow noreferrer"
|
|
29
|
+
>
|
|
30
|
+
{children ? (
|
|
31
|
+
children
|
|
32
|
+
) : (
|
|
33
|
+
<>
|
|
34
|
+
<span className="govuk-visually-hidden">Emergency</span> Exit this page
|
|
35
|
+
</>
|
|
36
|
+
)}
|
|
37
|
+
</a>
|
|
38
|
+
</div>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
type FeedbackProps = {
|
|
4
|
+
title?: string;
|
|
5
|
+
class?: string;
|
|
6
|
+
children?: ReactNode;
|
|
7
|
+
[key: string]: unknown;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export default function Feedback({ title, class: className, children, ...rest }: FeedbackProps) {
|
|
11
|
+
const classes = ["govuk-feedback govuk-width-container", className ?? ""]
|
|
12
|
+
.filter(Boolean)
|
|
13
|
+
.join(" ");
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<div className={classes} {...rest}>
|
|
17
|
+
<div className="govuk-grid-row">
|
|
18
|
+
<div className="govuk-grid-column-two-thirds">
|
|
19
|
+
<h2 className="govuk-feedback__title">{title}</h2>
|
|
20
|
+
{children != null && children !== "" ? (
|
|
21
|
+
<div className="govuk-feedback__body">{children}</div>
|
|
22
|
+
) : null}
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
@@ -2,12 +2,13 @@ import { ReactNode } from 'react';
|
|
|
2
2
|
|
|
3
3
|
type FieldsetLegendProps = {
|
|
4
4
|
size?: "small" | "medium" | "large" | "xl";
|
|
5
|
+
isPageHeading?: boolean;
|
|
5
6
|
class?: string;
|
|
6
7
|
children?: ReactNode;
|
|
7
8
|
[key: string]: unknown;
|
|
8
9
|
};
|
|
9
10
|
|
|
10
|
-
export default function FieldsetLegend({ size, class: className, children, ...rest }: FieldsetLegendProps) {
|
|
11
|
+
export default function FieldsetLegend({ size, isPageHeading, class: className, children, ...rest }: FieldsetLegendProps) {
|
|
11
12
|
const classes = [
|
|
12
13
|
"govuk-fieldset__legend",
|
|
13
14
|
({ "small": "govuk-fieldset__legend--s", "medium": "govuk-fieldset__legend--m", "large": "govuk-fieldset__legend--l", "xl": "govuk-fieldset__legend--xl" }[size] ?? ""),
|
|
@@ -18,7 +19,9 @@ export default function FieldsetLegend({ size, class: className, children, ...re
|
|
|
18
19
|
|
|
19
20
|
return (
|
|
20
21
|
<legend className={classes} {...rest}>
|
|
21
|
-
{
|
|
22
|
+
{isPageHeading
|
|
23
|
+
? <h1 className="govuk-fieldset__heading">{children ?? ""}</h1>
|
|
24
|
+
: children ?? ""}
|
|
22
25
|
</legend>
|
|
23
26
|
);
|
|
24
27
|
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
function FooterCrown() {
|
|
4
|
+
return (
|
|
5
|
+
<svg
|
|
6
|
+
focusable="false"
|
|
7
|
+
role="presentation"
|
|
8
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
9
|
+
viewBox="0 0 64 60"
|
|
10
|
+
height="30"
|
|
11
|
+
width="32"
|
|
12
|
+
fill="currentcolor"
|
|
13
|
+
className="govuk-footer__crown"
|
|
14
|
+
>
|
|
15
|
+
<g>
|
|
16
|
+
<circle cx="20" cy="17.6" r="3.7" />
|
|
17
|
+
<circle cx="10.2" cy="23.5" r="3.7" />
|
|
18
|
+
<circle cx="3.7" cy="33.2" r="3.7" />
|
|
19
|
+
<circle cx="31.7" cy="30.6" r="3.7" />
|
|
20
|
+
<circle cx="43.3" cy="17.6" r="3.7" />
|
|
21
|
+
<circle cx="53.2" cy="23.5" r="3.7" />
|
|
22
|
+
<circle cx="59.7" cy="33.2" r="3.7" />
|
|
23
|
+
<circle cx="31.7" cy="30.6" r="3.7" />
|
|
24
|
+
<path d="M33.1,9.8c.2-.1.3-.3.5-.5l4.6,2.4v-6.8l-4.6,1.5c-.1-.2-.3-.3-.5-.5l1.9-5.9h-6.7l1.9,5.9c-.2.1-.3.3-.5.5l-4.6-1.5v6.8l4.6-2.4c.1.2.3.3.5.5l-2.6,8c-.9,2.8,1.2,5.7,4.1,5.7h0c3,0,5.1-2.9,4.1-5.7l-2.6-8ZM37,37.9s-3.4,3.8-4.1,6.1c2.2,0,4.2-.5,6.4-2.8l-.7,8.5c-2-2.8-4.4-4.1-5.7-3.8.1,3.1.5,6.7,5.8,7.2,3.7.3,6.7-1.5,7-3.8.4-2.6-2-4.3-3.7-1.6-1.4-4.5,2.4-6.1,4.9-3.2-1.9-4.5-1.8-7.7,2.4-10.9,3,4,2.6,7.3-1.2,11.1,2.4-1.3,6.2,0,4,4.6-1.2-2.8-3.7-2.2-4.2.2-.3,1.7.7,3.7,3,4.2,1.9.3,4.7-.9,7-5.9-1.3,0-2.4.7-3.9,1.7l2.4-8c.6,2.3,1.4,3.7,2.2,4.5.6-1.6.5-2.8,0-5.3l5,1.8c-2.6,3.6-5.2,8.7-7.3,17.5-7.4-1.1-15.7-1.7-24.5-1.7h0c-8.8,0-17.1.6-24.5,1.7-2.1-8.9-4.7-13.9-7.3-17.5l5-1.8c-.5,2.5-.6,3.7,0,5.3.8-.8,1.6-2.3,2.2-4.5l2.4,8c-1.5-1-2.6-1.7-3.9-1.7,2.3,5,5.2,6.2,7,5.9,2.3-.4,3.3-2.4,3-4.2-.5-2.4-3-3.1-4.2-.2-2.2-4.6,1.6-6,4-4.6-3.7-3.7-4.2-7.1-1.2-11.1,4.2,3.2,4.3,6.4,2.4,10.9,2.5-2.8,6.3-1.3,4.9,3.2-1.8-2.7-4.1-1-3.7,1.6.3,2.3,3.3,4.1,7,3.8,5.4-.5,5.7-4.2,5.8-7.2-1.3-.2-3.7,1-5.7,3.8l-.7-8.5c2.2,2.3,4.2,2.7,6.4,2.8-.7-2.3-4.1-6.1-4.1-6.1h10.6,0Z" />
|
|
25
|
+
</g>
|
|
26
|
+
</svg>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function FooterLicenceLogo() {
|
|
31
|
+
return (
|
|
32
|
+
<svg
|
|
33
|
+
aria-hidden="true"
|
|
34
|
+
focusable="false"
|
|
35
|
+
className="govuk-footer__licence-logo"
|
|
36
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
37
|
+
viewBox="0 0 483.2 195.7"
|
|
38
|
+
height="17"
|
|
39
|
+
width="41"
|
|
40
|
+
>
|
|
41
|
+
<path
|
|
42
|
+
fill="currentColor"
|
|
43
|
+
d="M421.5 142.8V.1l-50.7 32.3v161.1h112.4v-50.7zm-122.3-9.6A47.12 47.12 0 0 1 221 97.8c0-26 21.1-47.1 47.1-47.1 16.7 0 31.4 8.7 39.7 21.8l42.7-27.2A97.63 97.63 0 0 0 268.1 0c-36.5 0-68.3 20.1-85.1 49.7A98 98 0 0 0 97.8 0C43.9 0 0 43.9 0 97.8s43.9 97.8 97.8 97.8c36.5 0 68.3-20.1 85.1-49.7a97.76 97.76 0 0 0 149.6 25.4l19.4 22.2h3v-87.8h-80l24.3 27.5zM97.8 145c-26 0-47.1-21.1-47.1-47.1s21.1-47.1 47.1-47.1 47.2 21 47.2 47S123.8 145 97.8 145"
|
|
44
|
+
/>
|
|
45
|
+
</svg>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
type FooterNavItem = { href?: string; text?: string; attributes?: Record<string, string> };
|
|
50
|
+
type FooterNav = { title?: string; columns?: number; width?: string; items?: FooterNavItem[] };
|
|
51
|
+
type FooterMetaItem = { href?: string; text?: string; attributes?: Record<string, string> };
|
|
52
|
+
type FooterMeta = {
|
|
53
|
+
visuallyHiddenTitle?: string;
|
|
54
|
+
items?: FooterMetaItem[];
|
|
55
|
+
text?: string;
|
|
56
|
+
/** Re-authored meta content (raw govuk `meta.html`). */
|
|
57
|
+
content?: ReactNode;
|
|
58
|
+
};
|
|
59
|
+
type FooterLicence = {
|
|
60
|
+
text?: string;
|
|
61
|
+
/** Re-authored licence content (raw govuk `contentLicence.html`). */
|
|
62
|
+
content?: ReactNode;
|
|
63
|
+
} | null;
|
|
64
|
+
type FooterCopyright = {
|
|
65
|
+
text?: string;
|
|
66
|
+
/** Re-authored copyright content (raw govuk `copyright.html`). */
|
|
67
|
+
content?: ReactNode;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
type FooterProps = {
|
|
71
|
+
navigation?: FooterNav[];
|
|
72
|
+
meta?: FooterMeta;
|
|
73
|
+
contentLicence?: FooterLicence;
|
|
74
|
+
copyright?: FooterCopyright;
|
|
75
|
+
containerClasses?: string;
|
|
76
|
+
class?: string;
|
|
77
|
+
[key: string]: unknown;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export default function Footer({
|
|
81
|
+
navigation,
|
|
82
|
+
meta,
|
|
83
|
+
contentLicence,
|
|
84
|
+
copyright,
|
|
85
|
+
containerClasses,
|
|
86
|
+
class: className,
|
|
87
|
+
...rest
|
|
88
|
+
}: FooterProps) {
|
|
89
|
+
const classes = ['govuk-footer', className ?? ''].filter(Boolean).join(' ');
|
|
90
|
+
const containerClass = ['govuk-width-container', containerClasses ?? '']
|
|
91
|
+
.filter(Boolean)
|
|
92
|
+
.join(' ');
|
|
93
|
+
|
|
94
|
+
return (
|
|
95
|
+
<div className={classes} {...rest}>
|
|
96
|
+
<div className={containerClass}>
|
|
97
|
+
<FooterCrown />
|
|
98
|
+
{navigation && navigation.length > 0 && (
|
|
99
|
+
<>
|
|
100
|
+
<div className="govuk-footer__navigation">
|
|
101
|
+
{navigation.map((nav, i) => (
|
|
102
|
+
<div
|
|
103
|
+
key={i}
|
|
104
|
+
className={`govuk-footer__section govuk-grid-column-${nav.width ?? 'full'}`}
|
|
105
|
+
>
|
|
106
|
+
<h2 className="govuk-footer__heading govuk-heading-m">{nav.title}</h2>
|
|
107
|
+
{nav.items && nav.items.length > 0 && (
|
|
108
|
+
<ul
|
|
109
|
+
className={[
|
|
110
|
+
'govuk-footer__list',
|
|
111
|
+
nav.columns ? `govuk-footer__list--columns-${nav.columns}` : '',
|
|
112
|
+
]
|
|
113
|
+
.filter(Boolean)
|
|
114
|
+
.join(' ')}
|
|
115
|
+
>
|
|
116
|
+
{nav.items
|
|
117
|
+
.filter((item) => item.href && item.text)
|
|
118
|
+
.map((item, j) => (
|
|
119
|
+
<li key={j} className="govuk-footer__list-item">
|
|
120
|
+
<a
|
|
121
|
+
className="govuk-footer__link"
|
|
122
|
+
href={item.href}
|
|
123
|
+
{...(item.attributes ?? {})}
|
|
124
|
+
>
|
|
125
|
+
{item.text}
|
|
126
|
+
</a>
|
|
127
|
+
</li>
|
|
128
|
+
))}
|
|
129
|
+
</ul>
|
|
130
|
+
)}
|
|
131
|
+
</div>
|
|
132
|
+
))}
|
|
133
|
+
</div>
|
|
134
|
+
<hr className="govuk-footer__section-break" />
|
|
135
|
+
</>
|
|
136
|
+
)}
|
|
137
|
+
<div className="govuk-footer__meta">
|
|
138
|
+
<div className="govuk-footer__meta-item govuk-footer__meta-item--grow">
|
|
139
|
+
{meta && (
|
|
140
|
+
<>
|
|
141
|
+
<h2 className="govuk-visually-hidden">
|
|
142
|
+
{meta.visuallyHiddenTitle ?? 'Support links'}
|
|
143
|
+
</h2>
|
|
144
|
+
{meta.items && meta.items.length > 0 && (
|
|
145
|
+
<ul className="govuk-footer__inline-list">
|
|
146
|
+
{meta.items.map((item, i) => (
|
|
147
|
+
<li key={i} className="govuk-footer__inline-list-item">
|
|
148
|
+
<a
|
|
149
|
+
className="govuk-footer__link"
|
|
150
|
+
href={item.href}
|
|
151
|
+
{...(item.attributes ?? {})}
|
|
152
|
+
>
|
|
153
|
+
{item.text}
|
|
154
|
+
</a>
|
|
155
|
+
</li>
|
|
156
|
+
))}
|
|
157
|
+
</ul>
|
|
158
|
+
)}
|
|
159
|
+
{(meta.content || meta.text) && (
|
|
160
|
+
<div className="govuk-footer__meta-custom">
|
|
161
|
+
{meta.content ?? meta.text}
|
|
162
|
+
</div>
|
|
163
|
+
)}
|
|
164
|
+
</>
|
|
165
|
+
)}
|
|
166
|
+
{contentLicence !== null && (
|
|
167
|
+
<>
|
|
168
|
+
<FooterLicenceLogo />
|
|
169
|
+
<span className="govuk-footer__licence-description">
|
|
170
|
+
{contentLicence && (contentLicence.content || contentLicence.text) ? (
|
|
171
|
+
contentLicence.content ?? contentLicence.text
|
|
172
|
+
) : (
|
|
173
|
+
<>
|
|
174
|
+
All content is available under the{' '}
|
|
175
|
+
<a
|
|
176
|
+
className="govuk-footer__link"
|
|
177
|
+
href="https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/"
|
|
178
|
+
rel="license"
|
|
179
|
+
>
|
|
180
|
+
Open Government Licence v3.0
|
|
181
|
+
</a>
|
|
182
|
+
, except where otherwise stated
|
|
183
|
+
</>
|
|
184
|
+
)}
|
|
185
|
+
</span>
|
|
186
|
+
</>
|
|
187
|
+
)}
|
|
188
|
+
</div>
|
|
189
|
+
<div className="govuk-footer__meta-item">
|
|
190
|
+
<a
|
|
191
|
+
className="govuk-footer__link govuk-footer__copyright-logo"
|
|
192
|
+
href="https://www.nationalarchives.gov.uk/information-management/re-using-public-sector-information/uk-government-licensing-framework/crown-copyright/"
|
|
193
|
+
>
|
|
194
|
+
{copyright && (copyright.content || copyright.text)
|
|
195
|
+
? (copyright.content ?? copyright.text)
|
|
196
|
+
: '© Crown copyright'}
|
|
197
|
+
</a>
|
|
198
|
+
</div>
|
|
199
|
+
</div>
|
|
200
|
+
</div>
|
|
201
|
+
</div>
|
|
202
|
+
);
|
|
203
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
const CROWN_LOGO = `<svg
|
|
2
|
+
focusable="false"
|
|
3
|
+
role="img"
|
|
4
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
5
|
+
viewBox="0 0 324 60"
|
|
6
|
+
height="30"
|
|
7
|
+
width="162"
|
|
8
|
+
fill="currentcolor" class="govuk-header__logotype" aria-label="GOV.UK"
|
|
9
|
+
><title>GOV.UK</title> <g>
|
|
10
|
+
<circle cx="20" cy="17.6" r="3.7"/>
|
|
11
|
+
<circle cx="10.2" cy="23.5" r="3.7"/>
|
|
12
|
+
<circle cx="3.7" cy="33.2" r="3.7"/>
|
|
13
|
+
<circle cx="31.7" cy="30.6" r="3.7"/>
|
|
14
|
+
<circle cx="43.3" cy="17.6" r="3.7"/>
|
|
15
|
+
<circle cx="53.2" cy="23.5" r="3.7"/>
|
|
16
|
+
<circle cx="59.7" cy="33.2" r="3.7"/>
|
|
17
|
+
<circle cx="31.7" cy="30.6" r="3.7"/>
|
|
18
|
+
<path d="M33.1,9.8c.2-.1.3-.3.5-.5l4.6,2.4v-6.8l-4.6,1.5c-.1-.2-.3-.3-.5-.5l1.9-5.9h-6.7l1.9,5.9c-.2.1-.3.3-.5.5l-4.6-1.5v6.8l4.6-2.4c.1.2.3.3.5.5l-2.6,8c-.9,2.8,1.2,5.7,4.1,5.7h0c3,0,5.1-2.9,4.1-5.7l-2.6-8ZM37,37.9s-3.4,3.8-4.1,6.1c2.2,0,4.2-.5,6.4-2.8l-.7,8.5c-2-2.8-4.4-4.1-5.7-3.8.1,3.1.5,6.7,5.8,7.2,3.7.3,6.7-1.5,7-3.8.4-2.6-2-4.3-3.7-1.6-1.4-4.5,2.4-6.1,4.9-3.2-1.9-4.5-1.8-7.7,2.4-10.9,3,4,2.6,7.3-1.2,11.1,2.4-1.3,6.2,0,4,4.6-1.2-2.8-3.7-2.2-4.2.2-.3,1.7.7,3.7,3,4.2,1.9.3,4.7-.9,7-5.9-1.3,0-2.4.7-3.9,1.7l2.4-8c.6,2.3,1.4,3.7,2.2,4.5.6-1.6.5-2.8,0-5.3l5,1.8c-2.6,3.6-5.2,8.7-7.3,17.5-7.4-1.1-15.7-1.7-24.5-1.7h0c-8.8,0-17.1.6-24.5,1.7-2.1-8.9-4.7-13.9-7.3-17.5l5-1.8c-.5,2.5-.6,3.7,0,5.3.8-.8,1.6-2.3,2.2-4.5l2.4,8c-1.5-1-2.6-1.7-3.9-1.7,2.3,5,5.2,6.2,7,5.9,2.3-.4,3.3-2.4,3-4.2-.5-2.4-3-3.1-4.2-.2-2.2-4.6,1.6-6,4-4.6-3.7-3.7-4.2-7.1-1.2-11.1,4.2,3.2,4.3,6.4,2.4,10.9,2.5-2.8,6.3-1.3,4.9,3.2-1.8-2.7-4.1-1-3.7,1.6.3,2.3,3.3,4.1,7,3.8,5.4-.5,5.7-4.2,5.8-7.2-1.3-.2-3.7,1-5.7,3.8l-.7-8.5c2.2,2.3,4.2,2.7,6.4,2.8-.7-2.3-4.1-6.1-4.1-6.1h10.6,0Z"/>
|
|
19
|
+
</g>
|
|
20
|
+
<circle class="govuk-logo-dot" cx="226" cy="36" r="7.3"/>
|
|
21
|
+
<path d="M93.94 41.25c.4 1.81 1.2 3.21 2.21 4.62 1 1.4 2.21 2.41 3.61 3.21s3.21 1.2 5.22 1.2 3.61-.4 4.82-1c1.4-.6 2.41-1.4 3.21-2.41.8-1 1.4-2.01 1.61-3.01s.4-2.01.4-3.01v.14h-10.86v-7.02h20.07v24.08h-8.03v-5.56c-.6.8-1.38 1.61-2.19 2.41-.8.8-1.81 1.2-2.81 1.81-1 .4-2.21.8-3.41 1.2s-2.41.4-3.81.4a18.56 18.56 0 0 1-14.65-6.63c-1.6-2.01-3.01-4.41-3.81-7.02s-1.4-5.62-1.4-8.83.4-6.02 1.4-8.83a20.45 20.45 0 0 1 19.46-13.65c3.21 0 4.01.2 5.82.8 1.81.4 3.61 1.2 5.02 2.01 1.61.8 2.81 2.01 4.01 3.21s2.21 2.61 2.81 4.21l-7.63 4.41c-.4-1-1-1.81-1.61-2.61-.6-.8-1.4-1.4-2.21-2.01-.8-.6-1.81-1-2.81-1.4-1-.4-2.21-.4-3.61-.4-2.01 0-3.81.4-5.22 1.2-1.4.8-2.61 1.81-3.61 3.21s-1.61 2.81-2.21 4.62c-.4 1.81-.6 3.71-.6 5.42s.8 5.22.8 5.22Zm57.8-27.9c3.21 0 6.22.6 8.63 1.81 2.41 1.2 4.82 2.81 6.62 4.82S170.2 24.39 171 27s1.4 5.62 1.4 8.83-.4 6.02-1.4 8.83-2.41 5.02-4.01 7.02-4.01 3.61-6.62 4.82-5.42 1.81-8.63 1.81-6.22-.6-8.63-1.81-4.82-2.81-6.42-4.82-3.21-4.41-4.01-7.02-1.4-5.62-1.4-8.83.4-6.02 1.4-8.83 2.41-5.02 4.01-7.02 4.01-3.61 6.42-4.82 5.42-1.81 8.63-1.81Zm0 36.73c1.81 0 3.61-.4 5.02-1s2.61-1.81 3.61-3.01 1.81-2.81 2.21-4.41c.4-1.81.8-3.61.8-5.62 0-2.21-.2-4.21-.8-6.02s-1.2-3.21-2.21-4.62c-1-1.2-2.21-2.21-3.61-3.01s-3.21-1-5.02-1-3.61.4-5.02 1c-1.4.8-2.61 1.81-3.61 3.01s-1.81 2.81-2.21 4.62c-.4 1.81-.8 3.61-.8 5.62 0 2.41.2 4.21.8 6.02.4 1.81 1.2 3.21 2.21 4.41s2.21 2.21 3.61 3.01c1.4.8 3.21 1 5.02 1Zm36.32 7.96-12.24-44.15h9.83l8.43 32.77h.4l8.23-32.77h9.83L200.3 58.04h-12.24Zm74.14-7.96c2.18 0 3.51-.6 3.51-.6 1.2-.6 2.01-1 2.81-1.81s1.4-1.81 1.81-2.81a13 13 0 0 0 .8-4.01V13.9h8.63v28.15c0 2.41-.4 4.62-1.4 6.62-.8 2.01-2.21 3.61-3.61 5.02s-3.41 2.41-5.62 3.21-4.62 1.2-7.02 1.2-5.02-.4-7.02-1.2c-2.21-.8-4.01-1.81-5.62-3.21s-2.81-3.01-3.61-5.02-1.4-4.21-1.4-6.62V13.9h8.63v26.95c0 1.61.2 3.01.8 4.01.4 1.2 1.2 2.21 2.01 2.81.8.8 1.81 1.4 2.81 1.81 0 0 1.34.6 3.51.6Zm34.22-36.18v18.92l15.65-18.92h10.82l-15.03 17.32 16.03 26.83h-10.21l-11.44-20.21-5.62 6.22v13.99h-8.83V13.9"/>
|
|
22
|
+
</svg>`;
|
|
23
|
+
|
|
24
|
+
type GovukHeaderProps = {
|
|
25
|
+
homepageUrl?: string;
|
|
26
|
+
productName?: string;
|
|
27
|
+
containerClasses?: string;
|
|
28
|
+
class?: string;
|
|
29
|
+
[key: string]: unknown;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export default function GovukHeader({
|
|
33
|
+
homepageUrl = '//gov.uk',
|
|
34
|
+
productName,
|
|
35
|
+
containerClasses = 'govuk-width-container',
|
|
36
|
+
class: className,
|
|
37
|
+
...rest
|
|
38
|
+
}: GovukHeaderProps) {
|
|
39
|
+
const classes = ['govuk-header', className ?? ''].filter(Boolean).join(' ');
|
|
40
|
+
const containerClass = ['govuk-header__container', containerClasses]
|
|
41
|
+
.filter(Boolean)
|
|
42
|
+
.join(' ');
|
|
43
|
+
|
|
44
|
+
const linkHtml = productName
|
|
45
|
+
? `${CROWN_LOGO}<span class="govuk-header__product-name">${productName}</span>`
|
|
46
|
+
: CROWN_LOGO;
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<div className={classes} {...rest}>
|
|
50
|
+
<div className={containerClass}>
|
|
51
|
+
<div className="govuk-header__logo">
|
|
52
|
+
<a
|
|
53
|
+
href={homepageUrl}
|
|
54
|
+
className="govuk-header__homepage-link"
|
|
55
|
+
dangerouslySetInnerHTML={{ __html: linkHtml }}
|
|
56
|
+
/>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
);
|
|
61
|
+
}
|
package/src/header/Header.tsx
CHANGED
|
@@ -3,16 +3,18 @@ import { ReactNode } from 'react';
|
|
|
3
3
|
type HeaderProps = {
|
|
4
4
|
href?: string;
|
|
5
5
|
class?: string;
|
|
6
|
+
containerClasses?: string;
|
|
6
7
|
children?: ReactNode;
|
|
7
8
|
[key: string]: unknown;
|
|
8
9
|
};
|
|
9
10
|
|
|
10
|
-
export default function Header({ href, class: className, children, ...rest }: HeaderProps) {
|
|
11
|
+
export default function Header({ href, class: className, containerClasses, children, ...rest }: HeaderProps) {
|
|
11
12
|
const classes = ["govuk-generic-header", className ?? ""].filter(Boolean).join(" ");
|
|
13
|
+
const container = ["govuk-generic-header__container", containerClasses || "govuk-width-container"].join(" ");
|
|
12
14
|
|
|
13
15
|
return (
|
|
14
16
|
<div className={classes} {...rest}>
|
|
15
|
-
<div className=
|
|
17
|
+
<div className={container}>
|
|
16
18
|
<div className="govuk-generic-header__logo">
|
|
17
19
|
<a className="govuk-generic-header__homepage-link" href={href}>
|
|
18
20
|
{children ?? ""}
|
package/src/index.ts
CHANGED
|
@@ -40,15 +40,22 @@ export { default as ErrorSummaryItem } from "./error-summary/ErrorSummaryItem";
|
|
|
40
40
|
export { default as ErrorSummaryList } from "./error-summary/ErrorSummaryList";
|
|
41
41
|
export { default as ErrorSummaryTitle } from "./error-summary/ErrorSummaryTitle";
|
|
42
42
|
export { default as ErrorSummary } from "./error-summary/ErrorSummary";
|
|
43
|
+
export { default as ExitThisPage } from "./exit-this-page/ExitThisPage";
|
|
43
44
|
export { default as FieldsetLegend } from "./fieldset/FieldsetLegend";
|
|
44
45
|
export { default as Fieldset } from "./fieldset/Fieldset";
|
|
46
|
+
export { default as Feedback } from "./feedback/Feedback";
|
|
45
47
|
export { default as FileUpload } from "./file-upload/FileUpload";
|
|
48
|
+
export { default as Footer } from "./footer/Footer";
|
|
46
49
|
export { default as FormGroup } from "./form-group/FormGroup";
|
|
50
|
+
export { default as GovukHeader } from "./govuk-header/GovukHeader";
|
|
47
51
|
export { default as Header } from "./header/Header";
|
|
48
52
|
export { default as Hint } from "./hint/Hint";
|
|
49
53
|
export { default as Input } from "./input/Input";
|
|
50
54
|
export { default as InputLabel } from "./input-label/InputLabel";
|
|
51
55
|
export { default as InsetText } from "./inset-text/InsetText";
|
|
56
|
+
export { default as Label } from "./label/Label";
|
|
57
|
+
export { default as LanguageNavigationItem } from "./language-navigation/LanguageNavigationItem";
|
|
58
|
+
export { default as LanguageNavigation } from "./language-navigation/LanguageNavigation";
|
|
52
59
|
export { default as Link } from "./link/Link";
|
|
53
60
|
export { default as ListItem } from "./list/ListItem";
|
|
54
61
|
export { default as List } from "./list/List";
|
|
@@ -62,8 +69,13 @@ export { default as PaginationList } from "./pagination/PaginationList";
|
|
|
62
69
|
export { default as PaginationNext } from "./pagination/PaginationNext";
|
|
63
70
|
export { default as PaginationPrev } from "./pagination/PaginationPrev";
|
|
64
71
|
export { default as Pagination } from "./pagination/Pagination";
|
|
72
|
+
export { default as PanelTitle } from "./panel/PanelTitle";
|
|
73
|
+
export { default as PanelBody } from "./panel/PanelBody";
|
|
74
|
+
export { default as PanelActions } from "./panel/PanelActions";
|
|
75
|
+
export { default as Panel } from "./panel/Panel";
|
|
65
76
|
export { default as PasswordInput } from "./password-input/PasswordInput";
|
|
66
77
|
export { default as PhaseBanner } from "./phase-banner/PhaseBanner";
|
|
78
|
+
export { default as PhaseBannerText } from "./phase-banner/PhaseBannerText";
|
|
67
79
|
export { default as RadioConditional } from "./radios/RadioConditional";
|
|
68
80
|
export { default as RadioDivider } from "./radios/RadioDivider";
|
|
69
81
|
export { default as RadioInput } from "./radios/RadioInput";
|
|
@@ -86,6 +98,12 @@ export { default as SummaryListKey } from "./summary-list/SummaryListKey";
|
|
|
86
98
|
export { default as SummaryListRow } from "./summary-list/SummaryListRow";
|
|
87
99
|
export { default as SummaryListValue } from "./summary-list/SummaryListValue";
|
|
88
100
|
export { default as SummaryList } from "./summary-list/SummaryList";
|
|
101
|
+
export { default as SummaryCard } from "./summary-card/SummaryCard";
|
|
102
|
+
export { default as SummaryCardTitleWrapper } from "./summary-card/SummaryCardTitleWrapper";
|
|
103
|
+
export { default as SummaryCardTitle } from "./summary-card/SummaryCardTitle";
|
|
104
|
+
export { default as SummaryCardActions } from "./summary-card/SummaryCardActions";
|
|
105
|
+
export { default as SummaryCardAction } from "./summary-card/SummaryCardAction";
|
|
106
|
+
export { default as SummaryCardContent } from "./summary-card/SummaryCardContent";
|
|
89
107
|
export { default as TableBody } from "./table/TableBody";
|
|
90
108
|
export { default as TableCaption } from "./table/TableCaption";
|
|
91
109
|
export { default as TableCell } from "./table/TableCell";
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
type LabelProps = {
|
|
4
|
+
size?: "small" | "medium" | "large" | "xl";
|
|
5
|
+
isPageHeading?: boolean;
|
|
6
|
+
class?: string;
|
|
7
|
+
children?: ReactNode;
|
|
8
|
+
[key: string]: unknown;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export default function Label({ size, isPageHeading = false, class: className, children, ...rest }: LabelProps) {
|
|
12
|
+
const classes = [
|
|
13
|
+
"govuk-label",
|
|
14
|
+
({ "small": "govuk-label--s", "medium": "govuk-label--m", "large": "govuk-label--l", "xl": "govuk-label--xl" }[size] ?? ""),
|
|
15
|
+
className ?? "",
|
|
16
|
+
]
|
|
17
|
+
.filter(Boolean)
|
|
18
|
+
.join(" ");
|
|
19
|
+
|
|
20
|
+
const label = (
|
|
21
|
+
<label className={classes} {...rest}>
|
|
22
|
+
{children ?? ""}
|
|
23
|
+
</label>
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
if (isPageHeading) {
|
|
27
|
+
return <h1 className="govuk-label-wrapper">{label}</h1>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return label;
|
|
31
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
type LanguageNavigationProps = {
|
|
4
|
+
ariaLabel?: string;
|
|
5
|
+
class?: string;
|
|
6
|
+
children?: ReactNode;
|
|
7
|
+
[key: string]: unknown;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export default function LanguageNavigation({
|
|
11
|
+
ariaLabel = "Language",
|
|
12
|
+
class: className,
|
|
13
|
+
children,
|
|
14
|
+
...rest
|
|
15
|
+
}: LanguageNavigationProps) {
|
|
16
|
+
const classes = ["govuk-language-navigation", className ?? ""]
|
|
17
|
+
.filter(Boolean)
|
|
18
|
+
.join(" ");
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<nav className={classes} aria-label={ariaLabel} {...rest}>
|
|
22
|
+
<ul className="govuk-language-navigation__list">
|
|
23
|
+
{children}
|
|
24
|
+
</ul>
|
|
25
|
+
</nav>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
type LanguageNavigationItemProps = {
|
|
4
|
+
href?: string;
|
|
5
|
+
current?: boolean;
|
|
6
|
+
lang?: string;
|
|
7
|
+
dir?: string;
|
|
8
|
+
/** hreflang for link items; defaults to `lang` when omitted. */
|
|
9
|
+
hreflang?: string;
|
|
10
|
+
/** Visually-hidden description appended to a link item. */
|
|
11
|
+
languageDescriptionText?: string;
|
|
12
|
+
children?: ReactNode;
|
|
13
|
+
[key: string]: unknown;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export default function LanguageNavigationItem({
|
|
17
|
+
href,
|
|
18
|
+
current = false,
|
|
19
|
+
lang,
|
|
20
|
+
dir,
|
|
21
|
+
hreflang,
|
|
22
|
+
languageDescriptionText,
|
|
23
|
+
children,
|
|
24
|
+
...rest
|
|
25
|
+
}: LanguageNavigationItemProps) {
|
|
26
|
+
return (
|
|
27
|
+
<li className="govuk-language-navigation__list-item">
|
|
28
|
+
{current ? (
|
|
29
|
+
<span
|
|
30
|
+
className="govuk-language-navigation__text"
|
|
31
|
+
aria-current="true"
|
|
32
|
+
lang={lang}
|
|
33
|
+
dir={dir}
|
|
34
|
+
{...rest}
|
|
35
|
+
>
|
|
36
|
+
{children}
|
|
37
|
+
</span>
|
|
38
|
+
) : (
|
|
39
|
+
<a
|
|
40
|
+
className="govuk-language-navigation__link"
|
|
41
|
+
href={href}
|
|
42
|
+
rel="alternate"
|
|
43
|
+
lang={lang}
|
|
44
|
+
hrefLang={hreflang ?? lang}
|
|
45
|
+
dir={dir}
|
|
46
|
+
{...rest}
|
|
47
|
+
>
|
|
48
|
+
{children}
|
|
49
|
+
{languageDescriptionText ? (
|
|
50
|
+
<span className="govuk-visually-hidden"> {languageDescriptionText}</span>
|
|
51
|
+
) : null}
|
|
52
|
+
</a>
|
|
53
|
+
)}
|
|
54
|
+
</li>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
@@ -2,25 +2,38 @@ import { ReactNode } from 'react';
|
|
|
2
2
|
|
|
3
3
|
type PaginationItemProps = {
|
|
4
4
|
current?: boolean;
|
|
5
|
-
ellipsis?:
|
|
5
|
+
ellipsis?: boolean;
|
|
6
|
+
/** aria-label for the page link (e.g. "Page 2"). */
|
|
7
|
+
ariaLabel?: string;
|
|
6
8
|
class?: string;
|
|
7
9
|
children?: ReactNode;
|
|
8
10
|
[key: string]: unknown;
|
|
9
11
|
};
|
|
10
12
|
|
|
11
|
-
export default function PaginationItem({ current, ellipsis, class: className, children, ...rest }: PaginationItemProps) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
ellipsis ? (
|
|
13
|
+
export default function PaginationItem({ current, ellipsis, ariaLabel, class: className, children, ...rest }: PaginationItemProps) {
|
|
14
|
+
if (ellipsis) {
|
|
15
|
+
return (
|
|
15
16
|
<li className="govuk-pagination__item govuk-pagination__item--ellipsis">
|
|
16
17
|
{children ?? "⋯"}
|
|
17
18
|
</li>
|
|
18
|
-
)
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const itemClasses = ["govuk-pagination__item", current ? "govuk-pagination__item--current" : ""]
|
|
23
|
+
.filter(Boolean)
|
|
24
|
+
.join(" ");
|
|
25
|
+
const linkClasses = ["govuk-link govuk-pagination__link", className ?? ""].filter(Boolean).join(" ");
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<li className={itemClasses}>
|
|
29
|
+
<a
|
|
30
|
+
className={linkClasses}
|
|
31
|
+
aria-label={ariaLabel}
|
|
32
|
+
aria-current={current ? "page" : undefined}
|
|
33
|
+
{...rest}
|
|
34
|
+
>
|
|
35
|
+
{children ?? ""}
|
|
36
|
+
</a>
|
|
37
|
+
</li>
|
|
25
38
|
);
|
|
26
39
|
}
|
|
@@ -1,26 +1,48 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
2
|
|
|
3
3
|
type PaginationNextProps = {
|
|
4
|
+
/** Block-level layout (no numbered items, just prev/next). */
|
|
5
|
+
block?: boolean;
|
|
6
|
+
/** Descriptive label shown alongside the title (block layout only). */
|
|
7
|
+
labelText?: string;
|
|
4
8
|
class?: string;
|
|
5
9
|
children?: ReactNode;
|
|
6
10
|
[key: string]: unknown;
|
|
7
11
|
};
|
|
8
12
|
|
|
9
|
-
|
|
13
|
+
const arrow = (
|
|
14
|
+
<svg className="govuk-pagination__icon govuk-pagination__icon--next" xmlns="http://www.w3.org/2000/svg" height="13" width="15" aria-hidden="true" focusable="false" viewBox="0 0 15 13">
|
|
15
|
+
<path d="m8.107-0.0078125-1.4136 1.414 4.2926 4.293h-12.986v2h12.896l-4.1855 3.9766 1.377 1.4492 6.7441-6.4062-6.7246-6.7266z"></path>
|
|
16
|
+
</svg>
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
export default function PaginationNext({ block, labelText, class: className, children, ...rest }: PaginationNextProps) {
|
|
10
20
|
const classes = ["govuk-link govuk-pagination__link", className ?? ""].filter(Boolean).join(" ");
|
|
21
|
+
const titleClasses = [
|
|
22
|
+
"govuk-pagination__link-title",
|
|
23
|
+
block && !labelText ? "govuk-pagination__link-title--decorated" : "",
|
|
24
|
+
]
|
|
25
|
+
.filter(Boolean)
|
|
26
|
+
.join(" ");
|
|
11
27
|
|
|
12
28
|
return (
|
|
13
29
|
<div className="govuk-pagination__next">
|
|
14
30
|
<a className={classes} rel="next" {...rest}>
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
31
|
+
{block && arrow}
|
|
32
|
+
<span className={titleClasses}>
|
|
33
|
+
{children ?? (
|
|
34
|
+
<>
|
|
35
|
+
Next<span className="govuk-visually-hidden"> page</span>
|
|
36
|
+
</>
|
|
37
|
+
)}
|
|
20
38
|
</span>
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
39
|
+
{labelText && block && (
|
|
40
|
+
<>
|
|
41
|
+
<span className="govuk-visually-hidden">:</span>
|
|
42
|
+
<span className="govuk-pagination__link-label">{labelText}</span>
|
|
43
|
+
</>
|
|
44
|
+
)}
|
|
45
|
+
{!block && arrow}
|
|
24
46
|
</a>
|
|
25
47
|
</div>
|
|
26
48
|
);
|
|
@@ -1,26 +1,47 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
2
|
|
|
3
3
|
type PaginationPrevProps = {
|
|
4
|
+
/** Block-level layout (no numbered items, just prev/next). */
|
|
5
|
+
block?: boolean;
|
|
6
|
+
/** Descriptive label shown alongside the title (block layout only). */
|
|
7
|
+
labelText?: string;
|
|
4
8
|
class?: string;
|
|
5
9
|
children?: ReactNode;
|
|
6
10
|
[key: string]: unknown;
|
|
7
11
|
};
|
|
8
12
|
|
|
9
|
-
|
|
13
|
+
const arrow = (
|
|
14
|
+
<svg className="govuk-pagination__icon govuk-pagination__icon--prev" xmlns="http://www.w3.org/2000/svg" height="13" width="15" aria-hidden="true" focusable="false" viewBox="0 0 15 13">
|
|
15
|
+
<path d="m6.5938-0.0078125-6.7266 6.7266 6.7441 6.4062 1.377-1.449-4.1856-3.9768h12.896v-2h-12.984l4.2931-4.293-1.414-1.414z"></path>
|
|
16
|
+
</svg>
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
export default function PaginationPrev({ block, labelText, class: className, children, ...rest }: PaginationPrevProps) {
|
|
10
20
|
const classes = ["govuk-link govuk-pagination__link", className ?? ""].filter(Boolean).join(" ");
|
|
21
|
+
const titleClasses = [
|
|
22
|
+
"govuk-pagination__link-title",
|
|
23
|
+
block && !labelText ? "govuk-pagination__link-title--decorated" : "",
|
|
24
|
+
]
|
|
25
|
+
.filter(Boolean)
|
|
26
|
+
.join(" ");
|
|
11
27
|
|
|
12
28
|
return (
|
|
13
29
|
<div className="govuk-pagination__prev">
|
|
14
30
|
<a className={classes} rel="prev" {...rest}>
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
</span>
|
|
31
|
+
{arrow}
|
|
32
|
+
<span className={titleClasses}>
|
|
33
|
+
{children ?? (
|
|
34
|
+
<>
|
|
35
|
+
Previous<span className="govuk-visually-hidden"> page</span>
|
|
36
|
+
</>
|
|
37
|
+
)}
|
|
23
38
|
</span>
|
|
39
|
+
{labelText && block && (
|
|
40
|
+
<>
|
|
41
|
+
<span className="govuk-visually-hidden">:</span>
|
|
42
|
+
<span className="govuk-pagination__link-label">{labelText}</span>
|
|
43
|
+
</>
|
|
44
|
+
)}
|
|
24
45
|
</a>
|
|
25
46
|
</div>
|
|
26
47
|
);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
type PanelProps = {
|
|
4
|
+
class?: string;
|
|
5
|
+
children?: ReactNode;
|
|
6
|
+
[key: string]: unknown;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export default function Panel({ class: className, children, ...rest }: PanelProps) {
|
|
10
|
+
const isInterruption = (className ?? "").includes("govuk-panel--interruption");
|
|
11
|
+
const classes = [
|
|
12
|
+
"govuk-panel",
|
|
13
|
+
isInterruption ? "" : "govuk-panel--confirmation",
|
|
14
|
+
className ?? "",
|
|
15
|
+
]
|
|
16
|
+
.filter(Boolean)
|
|
17
|
+
.join(" ");
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<div className={classes} {...rest}>
|
|
21
|
+
{children}
|
|
22
|
+
</div>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
type PanelActionsProps = {
|
|
4
|
+
class?: string;
|
|
5
|
+
children?: ReactNode;
|
|
6
|
+
[key: string]: unknown;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export default function PanelActions({ class: className, children, ...rest }: PanelActionsProps) {
|
|
10
|
+
const classes = ["govuk-panel__actions", className ?? ""].filter(Boolean).join(" ");
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<div className={classes} {...rest}>
|
|
14
|
+
{children}
|
|
15
|
+
</div>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
type PanelBodyProps = {
|
|
4
|
+
class?: string;
|
|
5
|
+
children?: ReactNode;
|
|
6
|
+
[key: string]: unknown;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export default function PanelBody({ class: className, children, ...rest }: PanelBodyProps) {
|
|
10
|
+
const classes = ["govuk-panel__body", className ?? ""].filter(Boolean).join(" ");
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<div className={classes} {...rest}>
|
|
14
|
+
{children}
|
|
15
|
+
</div>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
type PanelTitleProps = {
|
|
4
|
+
class?: string;
|
|
5
|
+
children?: ReactNode;
|
|
6
|
+
[key: string]: unknown;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export default function PanelTitle({ class: className, children, ...rest }: PanelTitleProps) {
|
|
10
|
+
const classes = ["govuk-panel__title", className ?? ""].filter(Boolean).join(" ");
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<h1 className={classes} {...rest}>
|
|
14
|
+
{children}
|
|
15
|
+
</h1>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
@@ -7,7 +7,7 @@ type PhaseBannerProps = {
|
|
|
7
7
|
};
|
|
8
8
|
|
|
9
9
|
export default function PhaseBanner({ class: className, children, ...rest }: PhaseBannerProps) {
|
|
10
|
-
const classes = ["govuk-phase-banner", className ?? ""].filter(Boolean).join(" ");
|
|
10
|
+
const classes = ["govuk-phase-banner govuk-width-container", className ?? ""].filter(Boolean).join(" ");
|
|
11
11
|
|
|
12
12
|
return (
|
|
13
13
|
<div className={classes} {...rest}>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
type PhaseBannerTextProps = {
|
|
4
|
+
class?: string;
|
|
5
|
+
children?: ReactNode;
|
|
6
|
+
[key: string]: unknown;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export default function PhaseBannerText({ class: className, children, ...rest }: PhaseBannerTextProps) {
|
|
10
|
+
const classes = ["govuk-phase-banner__text", className ?? ""].filter(Boolean).join(" ");
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<span className={classes} {...rest}>
|
|
14
|
+
{children ?? ""}
|
|
15
|
+
</span>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
@@ -3,12 +3,40 @@ import { ReactNode } from 'react';
|
|
|
3
3
|
type ServiceNavigationProps = {
|
|
4
4
|
sideNav?: boolean;
|
|
5
5
|
inverse?: boolean;
|
|
6
|
+
serviceName?: string;
|
|
7
|
+
serviceUrl?: string;
|
|
8
|
+
navigationId?: string;
|
|
9
|
+
menuButtonText?: string;
|
|
10
|
+
ariaLabel?: string;
|
|
11
|
+
/** Whether to render the navigation `<nav>` (omitted when there are no items). */
|
|
12
|
+
hasNavigation?: boolean;
|
|
13
|
+
/** Show the mobile menu toggle. Defaults to true when there is >1 item. */
|
|
14
|
+
collapseNavigationOnMobile?: boolean;
|
|
15
|
+
/** Raw HTML for the `end` slot (e.g. language navigation). */
|
|
16
|
+
endSlot?: ReactNode;
|
|
17
|
+
/** Align the end slot inline (adds the inlining container class). */
|
|
18
|
+
endSlotInline?: boolean;
|
|
6
19
|
class?: string;
|
|
7
20
|
children?: ReactNode;
|
|
8
21
|
[key: string]: unknown;
|
|
9
22
|
};
|
|
10
23
|
|
|
11
|
-
export default function ServiceNavigation({
|
|
24
|
+
export default function ServiceNavigation({
|
|
25
|
+
sideNav,
|
|
26
|
+
inverse,
|
|
27
|
+
serviceName,
|
|
28
|
+
serviceUrl,
|
|
29
|
+
navigationId = "navigation",
|
|
30
|
+
menuButtonText = "Menu",
|
|
31
|
+
ariaLabel,
|
|
32
|
+
hasNavigation = true,
|
|
33
|
+
collapseNavigationOnMobile,
|
|
34
|
+
endSlot,
|
|
35
|
+
endSlotInline,
|
|
36
|
+
class: className,
|
|
37
|
+
children,
|
|
38
|
+
...rest
|
|
39
|
+
}: ServiceNavigationProps) {
|
|
12
40
|
const classes = [
|
|
13
41
|
"govuk-service-navigation",
|
|
14
42
|
sideNav ? "govuk-service-navigation--side-nav" : "",
|
|
@@ -18,17 +46,65 @@ export default function ServiceNavigation({ sideNav, inverse, class: className,
|
|
|
18
46
|
.filter(Boolean)
|
|
19
47
|
.join(" ");
|
|
20
48
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
49
|
+
const navLabel = ariaLabel ?? menuButtonText;
|
|
50
|
+
const showToggle = collapseNavigationOnMobile ?? false;
|
|
51
|
+
const useSection = serviceName !== undefined || endSlot !== undefined;
|
|
52
|
+
|
|
53
|
+
const containerClasses = [
|
|
54
|
+
"govuk-width-container",
|
|
55
|
+
endSlotInline ? "govuk-service-navigation__inlining-container" : "",
|
|
56
|
+
]
|
|
57
|
+
.filter(Boolean)
|
|
58
|
+
.join(" ");
|
|
59
|
+
|
|
60
|
+
const inner = (
|
|
61
|
+
<div className={containerClasses}>
|
|
62
|
+
<div className="govuk-service-navigation__container">
|
|
63
|
+
{serviceName !== undefined && (
|
|
64
|
+
<span className="govuk-service-navigation__service-name">
|
|
65
|
+
{serviceUrl !== undefined ? (
|
|
66
|
+
<a href={serviceUrl} className="govuk-service-navigation__link">
|
|
67
|
+
{serviceName}
|
|
68
|
+
</a>
|
|
69
|
+
) : (
|
|
70
|
+
<span className="govuk-service-navigation__text">{serviceName}</span>
|
|
71
|
+
)}
|
|
72
|
+
</span>
|
|
73
|
+
)}
|
|
74
|
+
{hasNavigation && (
|
|
75
|
+
<nav aria-label={navLabel} className="govuk-service-navigation__wrapper">
|
|
76
|
+
{showToggle && (
|
|
77
|
+
<button
|
|
78
|
+
type="button"
|
|
79
|
+
className="govuk-service-navigation__toggle govuk-js-service-navigation-toggle"
|
|
80
|
+
aria-controls={navigationId}
|
|
81
|
+
hidden
|
|
82
|
+
aria-hidden="true"
|
|
83
|
+
>
|
|
84
|
+
{menuButtonText}
|
|
85
|
+
</button>
|
|
86
|
+
)}
|
|
87
|
+
<ul className="govuk-service-navigation__list" id={navigationId}>
|
|
27
88
|
{children ?? ""}
|
|
28
89
|
</ul>
|
|
29
90
|
</nav>
|
|
30
|
-
|
|
91
|
+
)}
|
|
31
92
|
</div>
|
|
93
|
+
{endSlot}
|
|
94
|
+
</div>
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
if (useSection) {
|
|
98
|
+
return (
|
|
99
|
+
<section aria-label={ariaLabel ?? "Service information"} className={classes} data-module="govuk-service-navigation" {...rest}>
|
|
100
|
+
{inner}
|
|
101
|
+
</section>
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return (
|
|
106
|
+
<div className={classes} data-module="govuk-service-navigation" {...rest}>
|
|
107
|
+
{inner}
|
|
32
108
|
</div>
|
|
33
109
|
);
|
|
34
110
|
}
|
|
@@ -2,19 +2,41 @@ import { ReactNode } from 'react';
|
|
|
2
2
|
|
|
3
3
|
type ServiceNavigationItemProps = {
|
|
4
4
|
href?: string;
|
|
5
|
+
/** Current page — adds active styling + aria-current="page". */
|
|
6
|
+
current?: boolean;
|
|
7
|
+
/** Active section — adds active styling + aria-current="true". */
|
|
8
|
+
active?: boolean;
|
|
5
9
|
class?: string;
|
|
6
10
|
children?: ReactNode;
|
|
7
11
|
[key: string]: unknown;
|
|
8
12
|
};
|
|
9
13
|
|
|
10
|
-
export default function ServiceNavigationItem({ href, class: className, children, ...rest }: ServiceNavigationItemProps) {
|
|
11
|
-
const
|
|
14
|
+
export default function ServiceNavigationItem({ href, current, active, class: className, children, ...rest }: ServiceNavigationItemProps) {
|
|
15
|
+
const isActive = current || active;
|
|
16
|
+
const classes = [
|
|
17
|
+
"govuk-service-navigation__item",
|
|
18
|
+
isActive ? "govuk-service-navigation__item--active" : "",
|
|
19
|
+
className ?? "",
|
|
20
|
+
]
|
|
21
|
+
.filter(Boolean)
|
|
22
|
+
.join(" ");
|
|
23
|
+
|
|
24
|
+
const ariaCurrent = current ? "page" : active ? "true" : undefined;
|
|
25
|
+
const inner = isActive
|
|
26
|
+
? <strong className="govuk-service-navigation__active-fallback">{children ?? ""}</strong>
|
|
27
|
+
: children ?? "";
|
|
12
28
|
|
|
13
29
|
return (
|
|
14
|
-
<li className={classes}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
30
|
+
<li className={classes}>
|
|
31
|
+
{href !== undefined ? (
|
|
32
|
+
<a className="govuk-service-navigation__link" href={href} aria-current={ariaCurrent} {...rest}>
|
|
33
|
+
{inner}
|
|
34
|
+
</a>
|
|
35
|
+
) : (
|
|
36
|
+
<span className="govuk-service-navigation__text" aria-current={ariaCurrent} {...rest}>
|
|
37
|
+
{inner}
|
|
38
|
+
</span>
|
|
39
|
+
)}
|
|
18
40
|
</li>
|
|
19
41
|
);
|
|
20
42
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
type SummaryCardProps = {
|
|
4
|
+
class?: string;
|
|
5
|
+
children?: ReactNode;
|
|
6
|
+
[key: string]: unknown;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export default function SummaryCard({ class: className, children, ...rest }: SummaryCardProps) {
|
|
10
|
+
const classes = ["govuk-summary-card", className ?? ""].filter(Boolean).join(" ");
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<div className={classes} {...rest}>
|
|
14
|
+
{children ?? ""}
|
|
15
|
+
</div>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
type SummaryCardActionProps = {
|
|
4
|
+
class?: string;
|
|
5
|
+
children?: ReactNode;
|
|
6
|
+
[key: string]: unknown;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export default function SummaryCardAction({ class: className, children, ...rest }: SummaryCardActionProps) {
|
|
10
|
+
const classes = ["govuk-summary-card__action", className ?? ""].filter(Boolean).join(" ");
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<li className={classes} {...rest}>
|
|
14
|
+
{children ?? ""}
|
|
15
|
+
</li>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
type SummaryCardActionsProps = {
|
|
4
|
+
/** Render as a single-action wrapper (`<div>`) instead of a list (`<ul>`).
|
|
5
|
+
* govuk uses a div for exactly one action and a ul for multiple. */
|
|
6
|
+
single?: boolean;
|
|
7
|
+
class?: string;
|
|
8
|
+
children?: ReactNode;
|
|
9
|
+
[key: string]: unknown;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export default function SummaryCardActions({ single, class: className, children, ...rest }: SummaryCardActionsProps) {
|
|
13
|
+
const classes = ["govuk-summary-card__actions", className ?? ""].filter(Boolean).join(" ");
|
|
14
|
+
|
|
15
|
+
if (single) {
|
|
16
|
+
return (
|
|
17
|
+
<div className={classes} {...rest}>
|
|
18
|
+
{children ?? ""}
|
|
19
|
+
</div>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<ul className={classes} {...rest}>
|
|
25
|
+
{children ?? ""}
|
|
26
|
+
</ul>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
type SummaryCardContentProps = {
|
|
4
|
+
class?: string;
|
|
5
|
+
children?: ReactNode;
|
|
6
|
+
[key: string]: unknown;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export default function SummaryCardContent({ class: className, children, ...rest }: SummaryCardContentProps) {
|
|
10
|
+
const classes = ["govuk-summary-card__content", className ?? ""].filter(Boolean).join(" ");
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<div className={classes} {...rest}>
|
|
14
|
+
{children ?? ""}
|
|
15
|
+
</div>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
type SummaryCardTitleProps = {
|
|
4
|
+
class?: string;
|
|
5
|
+
children?: ReactNode;
|
|
6
|
+
[key: string]: unknown;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export default function SummaryCardTitle({ class: className, children, ...rest }: SummaryCardTitleProps) {
|
|
10
|
+
const classes = ["govuk-summary-card__title", className ?? ""].filter(Boolean).join(" ");
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<h2 className={classes} {...rest}>
|
|
14
|
+
{children ?? ""}
|
|
15
|
+
</h2>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
type SummaryCardTitleWrapperProps = {
|
|
4
|
+
class?: string;
|
|
5
|
+
children?: ReactNode;
|
|
6
|
+
[key: string]: unknown;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export default function SummaryCardTitleWrapper({ class: className, children, ...rest }: SummaryCardTitleWrapperProps) {
|
|
10
|
+
const classes = ["govuk-summary-card__title-wrapper", className ?? ""].filter(Boolean).join(" ");
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<div className={classes} {...rest}>
|
|
14
|
+
{children ?? ""}
|
|
15
|
+
</div>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
@@ -4,12 +4,13 @@ import { ReactNode } from 'react';
|
|
|
4
4
|
|
|
5
5
|
type TableHeaderProps = {
|
|
6
6
|
numeric?: boolean;
|
|
7
|
+
scope?: "col" | "row" | "colgroup" | "rowgroup";
|
|
7
8
|
class?: string;
|
|
8
9
|
children?: ReactNode;
|
|
9
10
|
[key: string]: unknown;
|
|
10
11
|
};
|
|
11
12
|
|
|
12
|
-
export default function TableHeader({ numeric, class: className, children, ...rest }: TableHeaderProps) {
|
|
13
|
+
export default function TableHeader({ numeric, scope = "col", class: className, children, ...rest }: TableHeaderProps) {
|
|
13
14
|
const classes = [
|
|
14
15
|
"govuk-table__header",
|
|
15
16
|
numeric ? "govuk-table__header--numeric" : "",
|
|
@@ -19,7 +20,7 @@ export default function TableHeader({ numeric, class: className, children, ...re
|
|
|
19
20
|
.join(" ");
|
|
20
21
|
|
|
21
22
|
return (
|
|
22
|
-
<th className={classes} scope=
|
|
23
|
+
<th className={classes} scope={scope} {...rest}>
|
|
23
24
|
{children ?? ""}
|
|
24
25
|
</th>
|
|
25
26
|
);
|