@uktrade/react-component-library 0.10.1

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 (90) hide show
  1. package/LICENSE +21 -0
  2. package/Readme.md +64 -0
  3. package/dist/components/ApiBoundary/ApiBoundary.d.ts +10 -0
  4. package/dist/components/ApiBoundary/ApiBoundary.d.ts.map +1 -0
  5. package/dist/components/ApiBoundary/ApiBoundary.js +7 -0
  6. package/dist/components/ApiBoundary/ApiBoundary.module.css +30 -0
  7. package/dist/components/ApiQuery/ApiCreateClient.d.ts +3 -0
  8. package/dist/components/ApiQuery/ApiCreateClient.d.ts.map +1 -0
  9. package/dist/components/ApiQuery/ApiCreateClient.js +11 -0
  10. package/dist/components/ApiQuery/ApiCreateHooks.d.ts +25 -0
  11. package/dist/components/ApiQuery/ApiCreateHooks.d.ts.map +1 -0
  12. package/dist/components/ApiQuery/ApiCreateHooks.js +55 -0
  13. package/dist/components/ApiQuery/ApiProvider.d.ts +30 -0
  14. package/dist/components/ApiQuery/ApiProvider.d.ts.map +1 -0
  15. package/dist/components/ApiQuery/ApiProvider.js +59 -0
  16. package/dist/components/ApiQuery/index.d.ts +4 -0
  17. package/dist/components/ApiQuery/index.d.ts.map +1 -0
  18. package/dist/components/ApiQuery/index.js +3 -0
  19. package/dist/components/Arrow/Arrow.d.ts +8 -0
  20. package/dist/components/Arrow/Arrow.d.ts.map +1 -0
  21. package/dist/components/Arrow/Arrow.js +12 -0
  22. package/dist/components/Arrow/Arrow.module.css +21 -0
  23. package/dist/components/Arrows/Arrows.d.ts +7 -0
  24. package/dist/components/Arrows/Arrows.d.ts.map +1 -0
  25. package/dist/components/Arrows/Arrows.js +6 -0
  26. package/dist/components/Arrows/Arrows.module.css +25 -0
  27. package/dist/components/BackLink.d.ts +9 -0
  28. package/dist/components/BackLink.d.ts.map +1 -0
  29. package/dist/components/BackLink.js +6 -0
  30. package/dist/components/Button.d.ts +8 -0
  31. package/dist/components/Button.d.ts.map +1 -0
  32. package/dist/components/Button.js +4 -0
  33. package/dist/components/ButtonGroup.d.ts +6 -0
  34. package/dist/components/ButtonGroup.d.ts.map +1 -0
  35. package/dist/components/ButtonGroup.js +6 -0
  36. package/dist/components/Colours.d.ts +20 -0
  37. package/dist/components/Colours.d.ts.map +1 -0
  38. package/dist/components/Colours.js +20 -0
  39. package/dist/components/LoadingSpinner/LoadingSpinner.d.ts +7 -0
  40. package/dist/components/LoadingSpinner/LoadingSpinner.d.ts.map +1 -0
  41. package/dist/components/LoadingSpinner/LoadingSpinner.js +6 -0
  42. package/dist/components/LoadingSpinner/LoadingSpinner.module.css +33 -0
  43. package/dist/components/SummaryItem/SummaryItem.d.ts +39 -0
  44. package/dist/components/SummaryItem/SummaryItem.d.ts.map +1 -0
  45. package/dist/components/SummaryItem/SummaryItem.js +25 -0
  46. package/dist/components/SummaryList/SummaryList.d.ts +17 -0
  47. package/dist/components/SummaryList/SummaryList.d.ts.map +1 -0
  48. package/dist/components/SummaryList/SummaryList.js +7 -0
  49. package/dist/components/SummaryList/SummaryList.module.css +14 -0
  50. package/dist/components/Tags/Tags.d.ts +16 -0
  51. package/dist/components/Tags/Tags.d.ts.map +1 -0
  52. package/dist/components/Tags/Tags.js +16 -0
  53. package/dist/components/Tags/Tags.module.css +17 -0
  54. package/dist/components/ViewFormItem/ViewFormItem.d.ts +11 -0
  55. package/dist/components/ViewFormItem/ViewFormItem.d.ts.map +1 -0
  56. package/dist/components/ViewFormItem/ViewFormItem.js +13 -0
  57. package/dist/components/ViewFormItem/ViewFormItem.module.css +11 -0
  58. package/dist/index.d.ts +14 -0
  59. package/dist/index.d.ts.map +1 -0
  60. package/dist/index.js +13 -0
  61. package/dist/utils/cn.d.ts +2 -0
  62. package/dist/utils/cn.d.ts.map +1 -0
  63. package/dist/utils/cn.js +3 -0
  64. package/package.json +78 -0
  65. package/src/components/ApiBoundary/ApiBoundary.module.css +30 -0
  66. package/src/components/ApiBoundary/ApiBoundary.tsx +44 -0
  67. package/src/components/Arrow/Arrow.module.css +21 -0
  68. package/src/components/Arrow/Arrow.tsx +41 -0
  69. package/src/components/Arrows/Arrows.module.css +25 -0
  70. package/src/components/Arrows/Arrows.tsx +26 -0
  71. package/src/components/BackLink.tsx +28 -0
  72. package/src/components/Button.tsx +18 -0
  73. package/src/components/ButtonGroup.tsx +16 -0
  74. package/src/components/Colours.tsx +20 -0
  75. package/src/components/Footer/.gitkeep +0 -0
  76. package/src/components/Header/.gitkeep +0 -0
  77. package/src/components/Hero/.gitkeep +0 -0
  78. package/src/components/LoadingSpinner/LoadingSpinner.module.css +33 -0
  79. package/src/components/LoadingSpinner/LoadingSpinner.tsx +19 -0
  80. package/src/components/NavBar/.gitkeep +0 -0
  81. package/src/components/SummaryItem/SummaryItem.tsx +96 -0
  82. package/src/components/SummaryList/SummaryList.module.css +14 -0
  83. package/src/components/SummaryList/SummaryList.tsx +64 -0
  84. package/src/components/Tags/Tags.module.css +17 -0
  85. package/src/components/Tags/Tags.tsx +39 -0
  86. package/src/components/ViewFormItem/ViewFormItem.module.css +11 -0
  87. package/src/components/ViewFormItem/ViewFormItem.tsx +41 -0
  88. package/src/index.ts +12 -0
  89. package/src/types/custom.d.ts +4 -0
  90. package/src/utils/cn.ts +3 -0
@@ -0,0 +1,39 @@
1
+ import type React from "react";
2
+ export interface SummaryItemConfig {
3
+ name: string;
4
+ value: React.ReactNode;
5
+ actions?: SummaryListAction[];
6
+ }
7
+ export type SummaryListAction = {
8
+ text: string;
9
+ href: string;
10
+ visuallyHidden?: string;
11
+ };
12
+ export interface SummaryListActionProps {
13
+ action: SummaryListAction;
14
+ }
15
+ export interface SummaryListActionsListProps {
16
+ actions?: SummaryListAction[];
17
+ }
18
+ interface SummaryItemProps {
19
+ name: string;
20
+ children: React.ReactNode;
21
+ actions?: SummaryListAction[];
22
+ }
23
+ /**
24
+ * Single action link
25
+ */
26
+ export declare const SummaryListAction: ({ action, }: SummaryListActionProps) => React.JSX.Element;
27
+ /**
28
+ * Actions container
29
+ * - Renders nothing if no actions
30
+ * - Renders a link if one action
31
+ * - Renders a list if multiple actions
32
+ */
33
+ export declare const SummaryListActionsList: ({ actions, }: SummaryListActionsListProps) => React.JSX.Element | null;
34
+ /**
35
+ * Standard GOV.UK Summary List row
36
+ */
37
+ export declare const SummaryItem: ({ name, children, actions, }: SummaryItemProps) => React.JSX.Element;
38
+ export {};
39
+ //# sourceMappingURL=SummaryItem.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SummaryItem.d.ts","sourceRoot":"","sources":["../../../src/components/SummaryItem/SummaryItem.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,OAAO,CAAC,EAAE,iBAAiB,EAAE,CAAC;CAC/B;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,iBAAiB,CAAC;CAC3B;AAED,MAAM,WAAW,2BAA2B;IAC1C,OAAO,CAAC,EAAE,iBAAiB,EAAE,CAAC;CAC/B;AAED,UAAU,gBAAgB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,OAAO,CAAC,EAAE,iBAAiB,EAAE,CAAC;CAC/B;AAED;;GAEG;AACH,eAAO,MAAM,iBAAiB,GAAI,aAE/B,sBAAsB,KAAG,KAAK,CAAC,GAAG,CAAC,OAYrC,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,GAAI,cAEpC,2BAA2B,KAAG,KAAK,CAAC,GAAG,CAAC,OAAO,GAAG,IAqBpD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW,GAAI,8BAIzB,gBAAgB,KAAG,KAAK,CAAC,GAAG,CAAC,OAQ/B,CAAC"}
@@ -0,0 +1,25 @@
1
+ "use client";
2
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
3
+ /**
4
+ * Single action link
5
+ */
6
+ export const SummaryListAction = ({ action, }) => {
7
+ return (_jsxs("a", { className: "govuk-link", href: action.href, children: [action.text, action.visuallyHidden && (_jsxs("span", { className: "govuk-visually-hidden", children: [" ", action.visuallyHidden] }))] }));
8
+ };
9
+ /**
10
+ * Actions container
11
+ * - Renders nothing if no actions
12
+ * - Renders a link if one action
13
+ * - Renders a list if multiple actions
14
+ */
15
+ export const SummaryListActionsList = ({ actions, }) => {
16
+ if (!actions || actions.length === 0)
17
+ return null;
18
+ return (_jsx("dd", { className: "govuk-summary-list__actions", children: actions.length === 1 ? (_jsx(SummaryListAction, { action: actions[0] })) : (_jsx("ul", { className: "govuk-summary-list__actions-list", children: actions.map((action, index) => (_jsx("li", { className: "govuk-summary-list__actions-list-item", children: _jsx(SummaryListAction, { action: action }) }, `${action.href}-${index}`))) })) }));
19
+ };
20
+ /**
21
+ * Standard GOV.UK Summary List row
22
+ */
23
+ export const SummaryItem = ({ name, children, actions, }) => {
24
+ return (_jsxs("div", { className: "govuk-summary-list__row", children: [_jsx("dt", { className: "govuk-summary-list__key", children: name }), _jsx("dd", { className: "govuk-summary-list__value", children: children }), _jsx(SummaryListActionsList, { actions: actions })] }));
25
+ };
@@ -0,0 +1,17 @@
1
+ import type React from "react";
2
+ import { SummaryListAction } from "../SummaryItem/SummaryItem";
3
+ export interface SummaryListProps extends React.HTMLAttributes<HTMLDListElement> {
4
+ title: string;
5
+ children?: React.ReactNode;
6
+ actions?: SummaryListAction[];
7
+ className?: string;
8
+ }
9
+ export declare const SummaryList: ({ title, children, className, ...props }: SummaryListProps) => import("react/jsx-runtime").JSX.Element;
10
+ export interface SummaryCardProps extends React.HTMLAttributes<HTMLDivElement> {
11
+ title: string;
12
+ children?: React.ReactNode;
13
+ actions?: SummaryListAction[];
14
+ className?: string;
15
+ }
16
+ export declare const SummaryCard: ({ title, children, actions, className, ...props }: SummaryCardProps) => import("react/jsx-runtime").JSX.Element;
17
+ //# sourceMappingURL=SummaryList.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SummaryList.d.ts","sourceRoot":"","sources":["../../../src/components/SummaryList/SummaryList.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAG/D,MAAM,WAAW,gBAAiB,SAAQ,KAAK,CAAC,cAAc,CAAC,gBAAgB,CAAC;IAC9E,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,OAAO,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,WAAW,GAAI,0CAA0C,gBAAgB,4CAOrF,CAAC;AAEF,MAAM,WAAW,gBAAiB,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IAC5E,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,OAAO,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,WAAW,GAAI,mDAAmD,gBAAgB,4CAgC9F,CAAC"}
@@ -0,0 +1,7 @@
1
+ "use client";
2
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import clsx from "clsx";
4
+ import { SummaryListAction } from "../SummaryItem/SummaryItem";
5
+ import styles from "./SummaryList.module.css";
6
+ export const SummaryList = ({ title, children, className, ...props }) => (_jsxs(_Fragment, { children: [title && _jsx("h2", { className: "govuk-heading-l", children: title }), _jsx("dl", { className: clsx("govuk-summary-list", className), ...props, children: children })] }));
7
+ export const SummaryCard = ({ title, children, actions, className, ...props }) => (_jsx("div", { className: clsx(styles.root, className), children: _jsxs("div", { className: "govuk-summary-card govuk-body", ...props, children: [_jsxs("div", { className: "govuk-summary-card__title-wrapper", children: [_jsx("h2", { className: "govuk-summary-card__title", children: title }), actions && (_jsx("ul", { className: clsx("govuk-summary-card__actions", styles.summaryCardTitleActions), children: actions.map((action) => (_jsx("li", { className: "govuk-summary-card__action", children: _jsx(SummaryListAction, { action: action }) }, action.text))) }))] }), _jsx("div", { className: clsx("govuk-summary-card__content", styles.govukSummaryCardContent), children: children })] }) }));
@@ -0,0 +1,14 @@
1
+ .root {
2
+ .govukSummaryCardContent {
3
+ display: table;
4
+ width: calc(100% - 40px);
5
+ table-layout: fixed;
6
+ border-collapse: collapse;
7
+ margin: 20px;
8
+ margin-top: 10px;
9
+ }
10
+
11
+ .summaryCardTitleActions {
12
+ font-weight: 400;
13
+ }
14
+ }
@@ -0,0 +1,16 @@
1
+ import type React from "react";
2
+ import { TagColours } from "../Colours";
3
+ export type TagProps = {
4
+ text: string;
5
+ colour: TagColours;
6
+ };
7
+ export declare const Tag: ({ text, colour }: TagProps) => React.JSX.Element;
8
+ export type TagsProps = {
9
+ children: React.ReactNode;
10
+ };
11
+ export declare const Tags: ({ children }: TagsProps) => React.JSX.Element;
12
+ export type TagsListProps = {
13
+ tags: TagProps[];
14
+ };
15
+ export declare const TagsList: ({ tags }: TagsListProps) => React.JSX.Element;
16
+ //# sourceMappingURL=Tags.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Tags.d.ts","sourceRoot":"","sources":["../../../src/components/Tags/Tags.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAGxC,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,UAAU,CAAC;CACpB,CAAC;AAEF,eAAO,MAAM,GAAG,GAAI,kBAAkB,QAAQ,KAAG,KAAK,CAAC,GAAG,CAAC,OAE1D,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,CAAC;AAEF,eAAO,MAAM,IAAI,GAAI,cAAc,SAAS,KAAG,KAAK,CAAC,GAAG,CAAC,OAExD,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,QAAQ,EAAE,CAAC;CAClB,CAAC;AAEF,eAAO,MAAM,QAAQ,GAAI,UAAU,aAAa,KAAG,KAAK,CAAC,GAAG,CAAC,OAU5D,CAAC"}
@@ -0,0 +1,16 @@
1
+ "use client";
2
+ import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import clsx from "clsx";
4
+ import { TagColours } from "../Colours";
5
+ import styles from "./Tags.module.css";
6
+ export const Tag = ({ text, colour }) => {
7
+ return _jsx("strong", { className: clsx("govuk-tag", colour, styles.tag), children: text });
8
+ };
9
+ export const Tags = ({ children }) => {
10
+ return _jsx("span", { className: clsx("govuk-tags", styles.root), children: children });
11
+ };
12
+ export const TagsList = ({ tags }) => {
13
+ if (!tags || tags.length === 0)
14
+ return _jsx(_Fragment, {});
15
+ return (_jsx(Tags, { children: tags.map((tag) => (_jsx(Tag, { text: tag.text, colour: tag.colour }, tag.text))) }));
16
+ };
@@ -0,0 +1,17 @@
1
+ .root {
2
+ display: inline-flex;
3
+ flex-wrap: wrap;
4
+
5
+ @media (max-width: 640px) {
6
+ float: none;
7
+ clear: left;
8
+ }
9
+
10
+ @media (min-width: 640px) {
11
+ float: right;
12
+ }
13
+
14
+ .tag:not(:last-child) {
15
+ margin-right: 0.5rem;
16
+ }
17
+ }
@@ -0,0 +1,11 @@
1
+ import type { ReactNode } from "react";
2
+ import { type TagProps } from "../Tags/Tags";
3
+ interface LinkAndTagItemProps {
4
+ name: string;
5
+ href: string;
6
+ children?: ReactNode;
7
+ tags?: TagProps[];
8
+ }
9
+ export declare const ViewFormItem: ({ name, href, children, tags, }: LinkAndTagItemProps) => import("react/jsx-runtime").JSX.Element;
10
+ export {};
11
+ //# sourceMappingURL=ViewFormItem.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ViewFormItem.d.ts","sourceRoot":"","sources":["../../../src/components/ViewFormItem/ViewFormItem.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,EAAY,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AAIvD,UAAU,mBAAmB;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC;CACnB;AAED,eAAO,MAAM,YAAY,GAAI,iCAK1B,mBAAmB,4CAmBrB,CAAC"}
@@ -0,0 +1,13 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import clsx from "clsx";
4
+ import { TagColours } from "../Colours";
5
+ import { TagsList } from "../Tags/Tags";
6
+ import styles from "./ViewFormItem.module.css";
7
+ export const ViewFormItem = ({ name, href, children, tags = [], }) => {
8
+ tags.push({
9
+ text: children ? "Completed" : "Not started",
10
+ colour: children ? TagColours.LightBlue : TagColours.Grey,
11
+ });
12
+ return (_jsxs("div", { className: clsx(styles.root, "view-form-item", "govuk-summary-list__row"), children: [_jsx("dt", { className: clsx(styles.key, "govuk-summary-list__key"), children: _jsx("a", { className: "govuk-link", href: href, children: name }) }), _jsx("dd", { className: "govuk-summary-list__value", children: children }), _jsx("dd", { className: clsx(styles.actions, "govuk-summary-list__actions"), children: _jsx(TagsList, { tags: tags }) })] }));
13
+ };
@@ -0,0 +1,11 @@
1
+ .root {
2
+ clear: both;
3
+
4
+ .key {
5
+ font-weight: normal;
6
+ }
7
+
8
+ & .govuk-tags {
9
+ float: none;
10
+ }
11
+ }
@@ -0,0 +1,14 @@
1
+ export * from "./components/SummaryList/SummaryList";
2
+ export * from "./components/SummaryItem/SummaryItem";
3
+ export * from "./components/ViewFormItem/ViewFormItem";
4
+ export * from "./components/Arrow/Arrow";
5
+ export * from "./components/Arrows/Arrows";
6
+ export * from "./components/Tags/Tags";
7
+ export * from "./components/Colours";
8
+ export * from "./components/Button";
9
+ export * from "./components/ButtonGroup";
10
+ export * from "./components/BackLink";
11
+ export * from "./components/LoadingSpinner/LoadingSpinner";
12
+ export * from "./components/ApiBoundary/ApiBoundary";
13
+ export * from "./components/ApiQuery";
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,sCAAsC,CAAC;AACrD,cAAc,sCAAsC,CAAC;AACrD,cAAc,wCAAwC,CAAC;AACvD,cAAc,0BAA0B,CAAC;AACzC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,4CAA4C,CAAC;AAC3D,cAAc,sCAAsC,CAAC;AACrD,cAAc,uBAAuB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,13 @@
1
+ export * from "./components/SummaryList/SummaryList";
2
+ export * from "./components/SummaryItem/SummaryItem";
3
+ export * from "./components/ViewFormItem/ViewFormItem";
4
+ export * from "./components/Arrow/Arrow";
5
+ export * from "./components/Arrows/Arrows";
6
+ export * from "./components/Tags/Tags";
7
+ export * from "./components/Colours";
8
+ export * from "./components/Button";
9
+ export * from "./components/ButtonGroup";
10
+ export * from "./components/BackLink";
11
+ export * from "./components/LoadingSpinner/LoadingSpinner";
12
+ export * from "./components/ApiBoundary/ApiBoundary";
13
+ export * from "./components/ApiQuery";
@@ -0,0 +1,2 @@
1
+ export declare function cn(...classes: (string | undefined | false)[]): string;
2
+ //# sourceMappingURL=cn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cn.d.ts","sourceRoot":"","sources":["../../src/utils/cn.ts"],"names":[],"mappings":"AAAA,wBAAgB,EAAE,CAAC,GAAG,OAAO,EAAE,CAAC,MAAM,GAAG,SAAS,GAAG,KAAK,CAAC,EAAE,UAE5D"}
@@ -0,0 +1,3 @@
1
+ export function cn(...classes) {
2
+ return classes.filter(Boolean).join(" ");
3
+ }
package/package.json ADDED
@@ -0,0 +1,78 @@
1
+ {
2
+ "name": "@uktrade/react-component-library",
3
+ "version": "0.10.1",
4
+ "description": "A collection of reusable React components following GOV.UK design patterns.",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "files": [
8
+ "dist",
9
+ "src"
10
+ ],
11
+ "scripts": {
12
+ "build": "tsc -p tsconfig.build.json && npm run copy:css",
13
+ "copy:css": "rsync -av --include='*/' --include='*.css' --exclude='*' src/ dist/",
14
+ "docs:build": "tsc -p docs/playground/tsconfig.docs.json",
15
+ "docs:start": "npx vite@latest docs/playground open",
16
+ "docs:vulnerability": "npx vite@latest --version && npm audit --audit-level=high",
17
+ "lint": "eslint .",
18
+ "lint:fix": "eslint . --fix",
19
+ "test": "vitest run --config tests/vitest.config.ts",
20
+ "test:watch": "vitest --watch --config tests/vitest.config.ts",
21
+ "test:ui": "vitest --ui --config tests/vitest.config.ts",
22
+ "coverage": "vitest run --coverage --config tests/vitest.config.ts"
23
+ },
24
+ "exports": {
25
+ ".": {
26
+ "types": "./dist/index.d.ts",
27
+ "default": "./dist/index.js"
28
+ }
29
+ },
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "git+https://github.com/uktrade/react-component-library.git"
33
+ },
34
+ "bugs": {
35
+ "url": "https://github.com/uktrade/react-component-library/issues"
36
+ },
37
+ "homepage": "https://github.com/uktrade/react-component-library#readme",
38
+ "keywords": [
39
+ "react-components",
40
+ "govuk"
41
+ ],
42
+ "author": "Mo",
43
+ "license": "MIT",
44
+ "type": "module",
45
+ "private": false,
46
+ "peerDependencies": {
47
+ "react": ">=19",
48
+ "react-dom": ">=19"
49
+ },
50
+ "devDependencies": {
51
+ "@eslint/js": "^9.39.2",
52
+ "@testing-library/jest-dom": "^6.9.1",
53
+ "@testing-library/react": "^16.3.2",
54
+ "@types/react": "^19.2.9",
55
+ "@types/react-dom": "^19.2.3",
56
+ "@typescript-eslint/eslint-plugin": "^8.53.1",
57
+ "@typescript-eslint/parser": "^8.53.1",
58
+ "@vitest/coverage-v8": "^4.0.18",
59
+ "@vitest/ui": "^4.0.18",
60
+ "eslint": "^9.39.2",
61
+ "eslint-plugin-react": "^7.37.5",
62
+ "globals": "^17.2.0",
63
+ "jsdom": "^27.4.0",
64
+ "openapi-typescript": "^7.10.1",
65
+ "typescript": "^5.9.3",
66
+ "typescript-eslint": "^8.53.1",
67
+ "vitest": "^4.0.18"
68
+ },
69
+ "engines": {
70
+ "npm": ">=11.6.2",
71
+ "node": ">=24.11.1"
72
+ },
73
+ "dependencies": {
74
+ "@tanstack/react-query": "^5.90.20",
75
+ "clsx": "^2.1.0",
76
+ "openapi-fetch": "^0.15.0"
77
+ }
78
+ }
@@ -0,0 +1,30 @@
1
+ .hods-loading-spinner {
2
+ display: flex;
3
+ flex-direction: column;
4
+ align-items: center;
5
+ justify-content: center;
6
+ padding-top: 1rem;
7
+ }
8
+
9
+ .hods-loading-spinner__spinner {
10
+ width: 80px;
11
+ height: 80px;
12
+ border: 12px solid #dee0e2;
13
+ border-top-color: #1d70b8; /* GOV.UK blue */
14
+ border-radius: 50%;
15
+ animation: hods-loading-spinner-rotate 1.5s linear infinite;
16
+ }
17
+
18
+ .hods-loading-spinner__content {
19
+ margin-top: 1rem;
20
+ text-align: center;
21
+ }
22
+
23
+ @keyframes hods-loading-spinner-rotate {
24
+ from {
25
+ transform: rotate(0deg);
26
+ }
27
+ to {
28
+ transform: rotate(360deg);
29
+ }
30
+ }
@@ -0,0 +1,44 @@
1
+ // import { LoadingBox } from "govuk-react";
2
+ import { LoadingSpinner } from "../LoadingSpinner/LoadingSpinner";
3
+ import styles from "./ApiBoundary.module.css";
4
+ import { Button } from "../Button";
5
+
6
+ interface ApiBoundaryProps {
7
+ isLoading: boolean;
8
+ isError: boolean;
9
+ error?: unknown;
10
+ onRetry?: () => void;
11
+ children: React.ReactNode;
12
+ }
13
+
14
+ /* Boundary for API-related states: loading, success, and error */
15
+ export const ApiBoundary = ({
16
+ isLoading,
17
+ isError,
18
+ error,
19
+ onRetry,
20
+ children,
21
+ }: ApiBoundaryProps) => (
22
+ <div className={styles.root} aria-live="polite">
23
+ {isLoading && <LoadingSpinner />}
24
+
25
+ {!isLoading && !isError && children}
26
+
27
+ {isError && (
28
+ <>
29
+ <div className={styles.errorBackdrop} />
30
+ <section className={styles.error}>
31
+ <h2 className="govuk-heading-m">Error!</h2>
32
+ <pre className={styles.description}>
33
+ {typeof error === "string" ? error : JSON.stringify(error, null, 2)}
34
+ </pre>
35
+
36
+ {/* TODO: Make this button optional since it cannot always be required */}
37
+ <Button variant="warning" onClick={onRetry}>
38
+ Retry
39
+ </Button>
40
+ </section>
41
+ </>
42
+ )}
43
+ </div>
44
+ );
@@ -0,0 +1,21 @@
1
+ .root {
2
+ display: flex;
3
+ align-items: center;
4
+ margin-bottom: 0.5rem;
5
+ }
6
+
7
+ .arrow {
8
+ background: #f3f2f1;
9
+ display: flex;
10
+ align-items: center;
11
+ justify-content: center;
12
+ padding-left: 1rem;
13
+ font-weight: bold;
14
+ color: #333;
15
+ transition: background 0.2s ease;
16
+ }
17
+
18
+ .arrow.active {
19
+ background: #1d70b8;
20
+ color: white;
21
+ }
@@ -0,0 +1,41 @@
1
+ "use client"
2
+
3
+ import type React from "react";
4
+ import { cn } from "../../utils/cn";
5
+ import styles from "./Arrow.module.css";
6
+
7
+ export type ArrowProps = React.JSX.IntrinsicElements["div"] & {
8
+ variant?: "start" | "middle" | "end";
9
+ height?: number; // in px
10
+ active?: boolean;
11
+ };
12
+
13
+ export const Arrow = ({
14
+ className,
15
+ variant = "middle",
16
+ active = false,
17
+ height = 40,
18
+ children,
19
+ ...props
20
+ }: ArrowProps) => {
21
+ const clipMap: Record<string, string> = {
22
+ start: "polygon(0% 0%, calc(100% - 20px) 0%, 100% 50%, calc(100% - 20px) 100%, 0% 100%)",
23
+ middle: "polygon(0% 0%, calc(100% - 20px) 0%, 100% 50%, calc(100% - 20px) 100%, 0% 100%, 20px 50%)",
24
+ end: "polygon(0% 0%, 100% 0%, 100% 50%, 100% 100%, 0% 100%, 20px 50%)",
25
+ };
26
+
27
+ return (
28
+ <div
29
+ {...props}
30
+ className={cn(styles.root, className)}
31
+ style={{ height }}
32
+ >
33
+ <div
34
+ className={cn(styles.arrow, active && styles.active)}
35
+ style={{ clipPath: clipMap[variant], height }}
36
+ >
37
+ {children}
38
+ </div>
39
+ </div>
40
+ );
41
+ };
@@ -0,0 +1,25 @@
1
+ .root {
2
+ & > * {
3
+ display: none;
4
+ }
5
+
6
+ .active {
7
+ display: block;
8
+ + *,
9
+ + * + * {
10
+ display: block;
11
+ }
12
+ }
13
+
14
+ @media (min-width: 30rem) {
15
+ & {
16
+ display: flex;
17
+ }
18
+ }
19
+
20
+ @media (min-width: 40rem) {
21
+ && > * {
22
+ display: block;
23
+ }
24
+ }
25
+ }
@@ -0,0 +1,26 @@
1
+ "use client"
2
+
3
+ import clsx from "clsx";
4
+ import type React from "react";
5
+ import { Arrow } from "../Arrow/Arrow";
6
+ import styles from "./Arrows.module.css";
7
+
8
+ export type ArrowsProps = React.JSX.IntrinsicElements["div"] & {
9
+ arrows: string[];
10
+ activeIndex: number;
11
+ };
12
+
13
+ export const Arrows = ({ className, arrows, activeIndex }: ArrowsProps) => (
14
+ <div className={clsx(styles.root, className)}>
15
+ {arrows.map((arrow, index) => (
16
+ <Arrow
17
+ key={arrow}
18
+ className={clsx(index === activeIndex && styles.active)}
19
+ active={index === activeIndex}
20
+ variant={index === 0 ? "start" : index === arrows.length - 1 ? "end" : "middle"}
21
+ >
22
+ {arrow}
23
+ </Arrow>
24
+ ))}
25
+ </div>
26
+ );
@@ -0,0 +1,28 @@
1
+ "use client"
2
+
3
+ import type { MouseEventHandler, ReactNode } from "react";
4
+ import clsx from "clsx";
5
+
6
+ export interface BackLinkProps {
7
+ text?: ReactNode;
8
+ href?: string;
9
+ onClick?: MouseEventHandler<HTMLAnchorElement>;
10
+ className?: string; // ToDo: Improve additional classes, hard to override default styles
11
+ }
12
+
13
+ export function BackLink({
14
+ text = "Back",
15
+ href = "/",
16
+ onClick,
17
+ className,
18
+ }: BackLinkProps) {
19
+ return (
20
+ <a
21
+ href={href}
22
+ onClick={onClick}
23
+ className={clsx("govuk-back-link", className)}
24
+ >
25
+ {text}
26
+ </a>
27
+ );
28
+ }
@@ -0,0 +1,18 @@
1
+ "use client"
2
+
3
+ import clsx from "clsx";
4
+ import type { JSX, ReactNode } from "react";
5
+
6
+ type Props = JSX.IntrinsicElements["button"] & {
7
+ children: ReactNode;
8
+ variant?: "primary" | "secondary" | "warning";
9
+ };
10
+
11
+ export const Button = ({ variant = "primary", className, ...props }: Props) => (
12
+ <button
13
+ className={clsx("govuk-button", `govuk-button--${variant}`, className)}
14
+ aria-disabled={props.disabled}
15
+ data-module="govuk-button"
16
+ {...props}
17
+ />
18
+ );
@@ -0,0 +1,16 @@
1
+ "use client"
2
+
3
+ import clsx from "clsx";
4
+ import type { ReactNode } from "react";
5
+
6
+ export type ButtonGroupProps = React.JSX.IntrinsicElements["div"] & {
7
+ children: ReactNode;
8
+ };
9
+
10
+ export const ButtonGroup = ({ className, children, ...props }: ButtonGroupProps): React.JSX.Element => {
11
+ return (
12
+ <div className={clsx("govuk-button-group", className)} {...props}>
13
+ {children}
14
+ </div>
15
+ );
16
+ };
@@ -0,0 +1,20 @@
1
+ export enum TagColours {
2
+ Grey = "govuk-tag--grey",
3
+ Green = "govuk-tag--green",
4
+ Turquoise = "govuk-tag--turquoise",
5
+ Blue = "govuk-tag--blue",
6
+ LightBlue = "govuk-tag--light-blue",
7
+ Purple = "govuk-tag--purple",
8
+ Pink = "govuk-tag--pink",
9
+ Red = "govuk-tag--red",
10
+ Orange = "govuk-tag--orange",
11
+ Yellow = "govuk-tag--yellow",
12
+ }
13
+
14
+ export type BackgroundType = "default" | "light" | "muted" | "white";
15
+ export enum BackgroundColours {
16
+ transparent = "transparent",
17
+ light = "#f8f8f8",
18
+ muted = "#eef1f5",
19
+ white = "#ffffff",
20
+ }
File without changes
File without changes
File without changes