@i-dot-ai-npm/component-library-react 0.0.3 → 0.0.5

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.
Files changed (39) hide show
  1. package/package.json +1 -1
  2. package/src/breadcrumbs/BreadcrumbItem.tsx +8 -0
  3. package/src/character-count/CharacterCount.tsx +5 -2
  4. package/src/contents-panel/ContentsPanel.tsx +28 -0
  5. package/src/contents-panel/ContentsPanelItem.tsx +37 -0
  6. package/src/contents-panel/ContentsPanelList.tsx +17 -0
  7. package/src/contents-panel/ContentsPanelListHeading.tsx +17 -0
  8. package/src/date-input/DateInputField.tsx +2 -2
  9. package/src/error-summary/ErrorSummaryItem.tsx +6 -3
  10. package/src/exit-this-page/ExitThisPage.tsx +40 -0
  11. package/src/feedback/Feedback.tsx +27 -0
  12. package/src/fieldset/FieldsetLegend.tsx +5 -2
  13. package/src/footer/Footer.tsx +203 -0
  14. package/src/govuk-header/GovukHeader.tsx +61 -0
  15. package/src/header/Header.tsx +4 -2
  16. package/src/index.ts +22 -0
  17. package/src/label/Label.tsx +31 -0
  18. package/src/language-navigation/LanguageNavigation.tsx +27 -0
  19. package/src/language-navigation/LanguageNavigationItem.tsx +56 -0
  20. package/src/pagination/PaginationItem.tsx +25 -12
  21. package/src/pagination/PaginationNext.tsx +31 -9
  22. package/src/pagination/PaginationPrev.tsx +30 -9
  23. package/src/panel/Panel.tsx +24 -0
  24. package/src/panel/PanelActions.tsx +17 -0
  25. package/src/panel/PanelBody.tsx +17 -0
  26. package/src/panel/PanelTitle.tsx +17 -0
  27. package/src/phase-banner/PhaseBanner.tsx +1 -1
  28. package/src/phase-banner/PhaseBannerText.tsx +17 -0
  29. package/src/service-navigation/ServiceNavigation.tsx +84 -8
  30. package/src/service-navigation/ServiceNavigationItem.tsx +28 -6
  31. package/src/summary-card/SummaryCard.tsx +17 -0
  32. package/src/summary-card/SummaryCardAction.tsx +17 -0
  33. package/src/summary-card/SummaryCardActions.tsx +28 -0
  34. package/src/summary-card/SummaryCardContent.tsx +17 -0
  35. package/src/summary-card/SummaryCardTitle.tsx +17 -0
  36. package/src/summary-card/SummaryCardTitleWrapper.tsx +17 -0
  37. package/src/table/TableHeader.tsx +3 -2
  38. package/src/toggle/Toggle.tsx +1 -5
  39. package/src/toggle/ToggleItem.tsx +1 -1
@@ -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?: string;
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
- return (
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
- <li className={["govuk-pagination__item", current ? "govuk-pagination__item--current" : ""].filter(Boolean).join(" ")}>
20
- <a className={["govuk-link govuk-pagination__link", className ?? ""].filter(Boolean).join(" ")} {...rest}>
21
- {children ?? ""}
22
- </a>
23
- </li>
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
- export default function PaginationNext({ class: className, children, ...rest }: PaginationNextProps) {
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
- <span className="govuk-pagination__link-title">
16
- {children ?? "Next"}
17
- <span className="govuk-visually-hidden">
18
- page
19
- </span>
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
- <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">
22
- <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>
23
- </svg>
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
- export default function PaginationPrev({ class: className, children, ...rest }: PaginationPrevProps) {
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
- <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">
16
- <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>
17
- </svg>
18
- <span className="govuk-pagination__link-title">
19
- {children ?? "Previous"}
20
- <span className="govuk-visually-hidden">
21
- page
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({ sideNav, inverse, class: className, children, ...rest }: ServiceNavigationProps) {
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
- return (
22
- <div className={classes} data-module="govuk-service-navigation" {...rest}>
23
- <div className="govuk-width-container">
24
- <div className="govuk-service-navigation__container">
25
- <nav className="govuk-service-navigation__wrapper" aria-label="Menu">
26
- <ul className="govuk-service-navigation__list" id="navigation">
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
- </div>
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 classes = ["govuk-service-navigation__item", className ?? ""].filter(Boolean).join(" ");
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} {...rest}>
15
- <a className="govuk-service-navigation__link" href={href}>
16
- {children ?? ""}
17
- </a>
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
+ }