@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.
- package/LICENSE +21 -0
- package/Readme.md +64 -0
- package/dist/components/ApiBoundary/ApiBoundary.d.ts +10 -0
- package/dist/components/ApiBoundary/ApiBoundary.d.ts.map +1 -0
- package/dist/components/ApiBoundary/ApiBoundary.js +7 -0
- package/dist/components/ApiBoundary/ApiBoundary.module.css +30 -0
- package/dist/components/ApiQuery/ApiCreateClient.d.ts +3 -0
- package/dist/components/ApiQuery/ApiCreateClient.d.ts.map +1 -0
- package/dist/components/ApiQuery/ApiCreateClient.js +11 -0
- package/dist/components/ApiQuery/ApiCreateHooks.d.ts +25 -0
- package/dist/components/ApiQuery/ApiCreateHooks.d.ts.map +1 -0
- package/dist/components/ApiQuery/ApiCreateHooks.js +55 -0
- package/dist/components/ApiQuery/ApiProvider.d.ts +30 -0
- package/dist/components/ApiQuery/ApiProvider.d.ts.map +1 -0
- package/dist/components/ApiQuery/ApiProvider.js +59 -0
- package/dist/components/ApiQuery/index.d.ts +4 -0
- package/dist/components/ApiQuery/index.d.ts.map +1 -0
- package/dist/components/ApiQuery/index.js +3 -0
- package/dist/components/Arrow/Arrow.d.ts +8 -0
- package/dist/components/Arrow/Arrow.d.ts.map +1 -0
- package/dist/components/Arrow/Arrow.js +12 -0
- package/dist/components/Arrow/Arrow.module.css +21 -0
- package/dist/components/Arrows/Arrows.d.ts +7 -0
- package/dist/components/Arrows/Arrows.d.ts.map +1 -0
- package/dist/components/Arrows/Arrows.js +6 -0
- package/dist/components/Arrows/Arrows.module.css +25 -0
- package/dist/components/BackLink.d.ts +9 -0
- package/dist/components/BackLink.d.ts.map +1 -0
- package/dist/components/BackLink.js +6 -0
- package/dist/components/Button.d.ts +8 -0
- package/dist/components/Button.d.ts.map +1 -0
- package/dist/components/Button.js +4 -0
- package/dist/components/ButtonGroup.d.ts +6 -0
- package/dist/components/ButtonGroup.d.ts.map +1 -0
- package/dist/components/ButtonGroup.js +6 -0
- package/dist/components/Colours.d.ts +20 -0
- package/dist/components/Colours.d.ts.map +1 -0
- package/dist/components/Colours.js +20 -0
- package/dist/components/LoadingSpinner/LoadingSpinner.d.ts +7 -0
- package/dist/components/LoadingSpinner/LoadingSpinner.d.ts.map +1 -0
- package/dist/components/LoadingSpinner/LoadingSpinner.js +6 -0
- package/dist/components/LoadingSpinner/LoadingSpinner.module.css +33 -0
- package/dist/components/SummaryItem/SummaryItem.d.ts +39 -0
- package/dist/components/SummaryItem/SummaryItem.d.ts.map +1 -0
- package/dist/components/SummaryItem/SummaryItem.js +25 -0
- package/dist/components/SummaryList/SummaryList.d.ts +17 -0
- package/dist/components/SummaryList/SummaryList.d.ts.map +1 -0
- package/dist/components/SummaryList/SummaryList.js +7 -0
- package/dist/components/SummaryList/SummaryList.module.css +14 -0
- package/dist/components/Tags/Tags.d.ts +16 -0
- package/dist/components/Tags/Tags.d.ts.map +1 -0
- package/dist/components/Tags/Tags.js +16 -0
- package/dist/components/Tags/Tags.module.css +17 -0
- package/dist/components/ViewFormItem/ViewFormItem.d.ts +11 -0
- package/dist/components/ViewFormItem/ViewFormItem.d.ts.map +1 -0
- package/dist/components/ViewFormItem/ViewFormItem.js +13 -0
- package/dist/components/ViewFormItem/ViewFormItem.module.css +11 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/utils/cn.d.ts +2 -0
- package/dist/utils/cn.d.ts.map +1 -0
- package/dist/utils/cn.js +3 -0
- package/package.json +78 -0
- package/src/components/ApiBoundary/ApiBoundary.module.css +30 -0
- package/src/components/ApiBoundary/ApiBoundary.tsx +44 -0
- package/src/components/Arrow/Arrow.module.css +21 -0
- package/src/components/Arrow/Arrow.tsx +41 -0
- package/src/components/Arrows/Arrows.module.css +25 -0
- package/src/components/Arrows/Arrows.tsx +26 -0
- package/src/components/BackLink.tsx +28 -0
- package/src/components/Button.tsx +18 -0
- package/src/components/ButtonGroup.tsx +16 -0
- package/src/components/Colours.tsx +20 -0
- package/src/components/Footer/.gitkeep +0 -0
- package/src/components/Header/.gitkeep +0 -0
- package/src/components/Hero/.gitkeep +0 -0
- package/src/components/LoadingSpinner/LoadingSpinner.module.css +33 -0
- package/src/components/LoadingSpinner/LoadingSpinner.tsx +19 -0
- package/src/components/NavBar/.gitkeep +0 -0
- package/src/components/SummaryItem/SummaryItem.tsx +96 -0
- package/src/components/SummaryList/SummaryList.module.css +14 -0
- package/src/components/SummaryList/SummaryList.tsx +64 -0
- package/src/components/Tags/Tags.module.css +17 -0
- package/src/components/Tags/Tags.tsx +39 -0
- package/src/components/ViewFormItem/ViewFormItem.module.css +11 -0
- package/src/components/ViewFormItem/ViewFormItem.tsx +41 -0
- package/src/index.ts +12 -0
- package/src/types/custom.d.ts +4 -0
- package/src/utils/cn.ts +3 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Department for Business and Trade
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/Readme.md
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# React Design System
|
|
2
|
+
|
|
3
|
+
A collection of reusable React components following GOV.UK design patterns.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
* [Installation](#installation)
|
|
10
|
+
* [Usage](#usage)
|
|
11
|
+
* [Development](#development)
|
|
12
|
+
* [Build](#build)
|
|
13
|
+
* [Playground](#playground)
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Installation WIP
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @uktrade/react-component-library
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**Peer Dependencies:**
|
|
24
|
+
|
|
25
|
+
* `react >= 19`
|
|
26
|
+
* `react-dom >= 19`
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Usage
|
|
31
|
+
|
|
32
|
+
Import components from the package:
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
import { SummaryList, SummaryItem } from "react-component-library";
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
You can use them directly in your React applications.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Development
|
|
43
|
+
|
|
44
|
+
### Build
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
git clone https://github.com/uktrade/react-component-library.git
|
|
48
|
+
cd react-component-library
|
|
49
|
+
nvm use
|
|
50
|
+
npm ci
|
|
51
|
+
npm run build
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Copies TypeScript output and `.css` files into `dist/`.
|
|
55
|
+
|
|
56
|
+
### Playground
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npm run build
|
|
60
|
+
npm run docs:build
|
|
61
|
+
npm run docs:start
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
This opens a Vite dev server with the playground for testing components.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
interface ApiBoundaryProps {
|
|
2
|
+
isLoading: boolean;
|
|
3
|
+
isError: boolean;
|
|
4
|
+
error?: unknown;
|
|
5
|
+
onRetry?: () => void;
|
|
6
|
+
children: React.ReactNode;
|
|
7
|
+
}
|
|
8
|
+
export declare const ApiBoundary: ({ isLoading, isError, error, onRetry, children, }: ApiBoundaryProps) => import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=ApiBoundary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ApiBoundary.d.ts","sourceRoot":"","sources":["../../../src/components/ApiBoundary/ApiBoundary.tsx"],"names":[],"mappings":"AAKA,UAAU,gBAAgB;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAGD,eAAO,MAAM,WAAW,GAAI,mDAMzB,gBAAgB,4CAuBlB,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
// import { LoadingBox } from "govuk-react";
|
|
3
|
+
import { LoadingSpinner } from "../LoadingSpinner/LoadingSpinner";
|
|
4
|
+
import styles from "./ApiBoundary.module.css";
|
|
5
|
+
import { Button } from "../Button";
|
|
6
|
+
/* Boundary for API-related states: loading, success, and error */
|
|
7
|
+
export const ApiBoundary = ({ isLoading, isError, error, onRetry, children, }) => (_jsxs("div", { className: styles.root, "aria-live": "polite", children: [isLoading && _jsx(LoadingSpinner, {}), !isLoading && !isError && children, isError && (_jsxs(_Fragment, { children: [_jsx("div", { className: styles.errorBackdrop }), _jsxs("section", { className: styles.error, children: [_jsx("h2", { className: "govuk-heading-m", children: "Error!" }), _jsx("pre", { className: styles.description, children: typeof error === "string" ? error : JSON.stringify(error, null, 2) }), _jsx(Button, { variant: "warning", onClick: onRetry, children: "Retry" })] })] }))] }));
|
|
@@ -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 @@
|
|
|
1
|
+
{"version":3,"file":"ApiCreateClient.d.ts","sourceRoot":"","sources":["../../../src/components/ApiQuery/ApiCreateClient.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAGnD,wBAAgB,eAAe,CAAC,KAAK,SAAS,EAAE,EAC9C,OAAO,CAAC,EAAE,aAAa,gEAWxB"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import createClient from "openapi-fetch";
|
|
2
|
+
// `extends {}` required to fix type error (Type 'Paths' does not satisfy the constraint '{}'.)
|
|
3
|
+
export function createApiClient(options) {
|
|
4
|
+
const defaultOptions = {
|
|
5
|
+
baseUrl: "/api",
|
|
6
|
+
credentials: "include",
|
|
7
|
+
};
|
|
8
|
+
// Merge/Override user options with the defaults
|
|
9
|
+
const finalOptions = { ...defaultOptions, ...options };
|
|
10
|
+
return createClient(finalOptions);
|
|
11
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { PathsWithMethod } from "openapi-typescript-helpers";
|
|
2
|
+
import { createApiClient } from "./ApiCreateClient";
|
|
3
|
+
export declare function createApiHooks<Paths extends {}>(client: ReturnType<typeof createApiClient<Paths>>): {
|
|
4
|
+
get: <P extends PathsWithMethod<Paths, "get">>(path: P, params?: any) => {
|
|
5
|
+
query: import("@tanstack/react-query").UseQueryResult<any, Error>;
|
|
6
|
+
state: {
|
|
7
|
+
data: any;
|
|
8
|
+
isLoading: boolean;
|
|
9
|
+
isError: boolean;
|
|
10
|
+
error: Error | null;
|
|
11
|
+
refetch: (options?: import("@tanstack/query-core").RefetchOptions) => Promise<import("@tanstack/query-core").QueryObserverResult<any, Error>>;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
post: <P extends PathsWithMethod<Paths, "post">>(path: P, params?: any) => {
|
|
15
|
+
query: import("@tanstack/react-query").UseQueryResult<any, Error>;
|
|
16
|
+
state: {
|
|
17
|
+
data: any;
|
|
18
|
+
isLoading: boolean;
|
|
19
|
+
isError: boolean;
|
|
20
|
+
error: Error | null;
|
|
21
|
+
refetch: (options?: import("@tanstack/query-core").RefetchOptions) => Promise<import("@tanstack/query-core").QueryObserverResult<any, Error>>;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=ApiCreateHooks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ApiCreateHooks.d.ts","sourceRoot":"","sources":["../../../src/components/ApiQuery/ApiCreateHooks.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAElE,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGpD,wBAAgB,cAAc,CAAC,KAAK,SAAS,EAAE,EAC7C,MAAM,EAAE,UAAU,CAAC,OAAO,eAAe,CAAC,KAAK,CAAC,CAAC;UAMzC,CAAC,SAAS,eAAe,CAAC,KAAK,EAAE,KAAK,CAAC,QACrC,CAAC,WACE,GAAG;;;;;;;;;;WAYP,CAAC,SAAS,eAAe,CAAC,KAAK,EAAE,MAAM,CAAC,QACvC,CAAC,WACE,GAAG;;;;;;;;;;EA6CjB"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { createApiClient } from "./ApiCreateClient";
|
|
3
|
+
import { useApi } from "./ApiProvider";
|
|
4
|
+
export function createApiHooks(client) {
|
|
5
|
+
// type GetParams<P extends PathsWithMethod<Paths, "get">> =
|
|
6
|
+
// Parameters<typeof client.GET<P>>[1];
|
|
7
|
+
return {
|
|
8
|
+
get: (path, params // GetParams<P> More work to be done to fight openapi-fetch’s internal generics!!!!
|
|
9
|
+
) => {
|
|
10
|
+
return useApi(["get", path, JSON.stringify(params ?? {})], async () => {
|
|
11
|
+
const res = await client.GET(path, params);
|
|
12
|
+
if (res.error)
|
|
13
|
+
throw res.error;
|
|
14
|
+
return res.data;
|
|
15
|
+
});
|
|
16
|
+
},
|
|
17
|
+
post: (path, params // GetParams<P> More work to be done to fight openapi-fetch’s internal generics!!!!
|
|
18
|
+
) => {
|
|
19
|
+
return useApi(["post", path, JSON.stringify(params ?? {})], async () => {
|
|
20
|
+
const res = await client.POST(path, params);
|
|
21
|
+
if (res.error)
|
|
22
|
+
throw res.error;
|
|
23
|
+
return res.data;
|
|
24
|
+
});
|
|
25
|
+
},
|
|
26
|
+
// TODO: implement other methods (put, delete), furthermore generalize the mutation method
|
|
27
|
+
// for all methods (No GET) to avoid React Query’s useQuery from running automatically on mount
|
|
28
|
+
// Same here (params?: any)
|
|
29
|
+
// postMutation: <P extends PathsWithMethod<Paths, "post">>(path: P, params?: any) => {
|
|
30
|
+
// return useApiMutation(async () => {
|
|
31
|
+
// const res = await client.POST(path, params);
|
|
32
|
+
// if (res.error) throw res.error;
|
|
33
|
+
// return res.data;
|
|
34
|
+
// });
|
|
35
|
+
// },
|
|
36
|
+
// mutation: <
|
|
37
|
+
// M extends "post" | "put" | "patch" | "delete",
|
|
38
|
+
// P extends PathsWithMethod<Paths, M>
|
|
39
|
+
// >(
|
|
40
|
+
// method: M,
|
|
41
|
+
// path: P,
|
|
42
|
+
// params?: any
|
|
43
|
+
// ) => {
|
|
44
|
+
// return useApiMutation(async () => {
|
|
45
|
+
// const res = await client[method.toUpperCase() as "POST" | "PUT" | "PATCH" | "DELETE"](path, params);
|
|
46
|
+
// if (res.error) throw res.error;
|
|
47
|
+
// return res.data;
|
|
48
|
+
// });
|
|
49
|
+
// }
|
|
50
|
+
// ToDo: Generalize this:
|
|
51
|
+
// const res = await client.POST(path, params);
|
|
52
|
+
// if (res.error) throw res.error;
|
|
53
|
+
// return res.data;
|
|
54
|
+
};
|
|
55
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type QueryKey } from "@tanstack/react-query";
|
|
2
|
+
import type { ReactNode } from "react";
|
|
3
|
+
export declare function ApiProvider({ children }: {
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
export type ApiQueryState<T> = {
|
|
7
|
+
data?: T;
|
|
8
|
+
isLoading: boolean;
|
|
9
|
+
isError: boolean;
|
|
10
|
+
error?: unknown;
|
|
11
|
+
refetch: () => void;
|
|
12
|
+
};
|
|
13
|
+
export declare function useApi<T>(key: QueryKey, queryFn: () => Promise<T>): {
|
|
14
|
+
query: import("@tanstack/react-query").UseQueryResult<import("@tanstack/query-core").NoInfer<T>, Error>;
|
|
15
|
+
state: {
|
|
16
|
+
data: import("@tanstack/query-core").NoInfer<T> | undefined;
|
|
17
|
+
isLoading: boolean;
|
|
18
|
+
isError: boolean;
|
|
19
|
+
error: Error | null;
|
|
20
|
+
refetch: (options?: import("@tanstack/query-core").RefetchOptions) => Promise<import("@tanstack/query-core").QueryObserverResult<import("@tanstack/query-core").NoInfer<T>, Error>>;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
export declare function useApiMutation<T>(mutationFn: () => Promise<T>): {
|
|
24
|
+
data: T | undefined;
|
|
25
|
+
isLoading: boolean;
|
|
26
|
+
isError: boolean;
|
|
27
|
+
error: Error | null;
|
|
28
|
+
mutate: import("@tanstack/react-query").UseMutateFunction<T, Error, void, unknown>;
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=ApiProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ApiProvider.d.ts","sourceRoot":"","sources":["../../../src/components/ApiQuery/ApiProvider.tsx"],"names":[],"mappings":"AAEA,OAAO,EAKL,KAAK,QAAQ,EACd,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAsBvC,wBAAgB,WAAW,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,2CAOhE;AAED,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI;IAC7B,IAAI,CAAC,EAAE,CAAC,CAAC;IACT,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAEF,wBAAgB,MAAM,CAAC,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC;;;;;;;;;EAgBjE;AAWD,wBAAgB,cAAc,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC;;;;;;EAU7D"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { QueryClient, QueryClientProvider, useQuery, useMutation } from "@tanstack/react-query";
|
|
4
|
+
// To avoid cache duplication bugs we make sure to have one single queryClient object
|
|
5
|
+
// per app.
|
|
6
|
+
let queryClient;
|
|
7
|
+
function getQueryClient() {
|
|
8
|
+
if (!queryClient) {
|
|
9
|
+
// Stores all query state, retries, and caching
|
|
10
|
+
queryClient = new QueryClient({
|
|
11
|
+
defaultOptions: {
|
|
12
|
+
queries: {
|
|
13
|
+
retry: false,
|
|
14
|
+
refetchOnWindowFocus: false,
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
return queryClient;
|
|
20
|
+
}
|
|
21
|
+
// Wrapper around `QueryClientProvider`
|
|
22
|
+
export function ApiProvider({ children }) {
|
|
23
|
+
return (
|
|
24
|
+
// Injects the client into React Query’s context
|
|
25
|
+
_jsx(QueryClientProvider, { client: getQueryClient(), children: children }));
|
|
26
|
+
}
|
|
27
|
+
export function useApi(key, queryFn) {
|
|
28
|
+
// From React Query queryKey and queryFn.
|
|
29
|
+
// `queryKey` is a unique identifier for this query (React Query uses it for caching and refetching).
|
|
30
|
+
// `queryFn` is the function that actually fetches the data, API call by using openapi-fetch module.
|
|
31
|
+
const query = useQuery({ queryKey: key, queryFn });
|
|
32
|
+
return {
|
|
33
|
+
query, // raw data to make sure you do not block full React Query object from propagating
|
|
34
|
+
state: {
|
|
35
|
+
data: query.data, // fetched data
|
|
36
|
+
isLoading: query.isFetching, // boolean for current fetch in progress
|
|
37
|
+
isError: query.isError, // boolean for error state
|
|
38
|
+
error: query.error, // error object if it failed
|
|
39
|
+
refetch: query.refetch, // function to manually re-run the query
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
// export function useApi<T>(key: QueryKey, queryFn: () => Promise<T>): ApiQueryState<T> {
|
|
44
|
+
// const { data, isFetching, isError, error, refetch } = useQuery({
|
|
45
|
+
// queryKey: key,
|
|
46
|
+
// queryFn,
|
|
47
|
+
// });
|
|
48
|
+
// return { data, isLoading: isFetching, isError, error, refetch };
|
|
49
|
+
// }
|
|
50
|
+
export function useApiMutation(mutationFn) {
|
|
51
|
+
const { data, isPending, isError, error, mutate } = useMutation({ mutationFn });
|
|
52
|
+
return {
|
|
53
|
+
data,
|
|
54
|
+
isLoading: isPending,
|
|
55
|
+
isError,
|
|
56
|
+
error,
|
|
57
|
+
mutate,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/ApiQuery/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type React from "react";
|
|
2
|
+
export type ArrowProps = React.JSX.IntrinsicElements["div"] & {
|
|
3
|
+
variant?: "start" | "middle" | "end";
|
|
4
|
+
height?: number;
|
|
5
|
+
active?: boolean;
|
|
6
|
+
};
|
|
7
|
+
export declare const Arrow: ({ className, variant, active, height, children, ...props }: ArrowProps) => import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
//# sourceMappingURL=Arrow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Arrow.d.ts","sourceRoot":"","sources":["../../../src/components/Arrow/Arrow.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,MAAM,MAAM,UAAU,GAAG,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,KAAK,CAAC,GAAG;IAC5D,OAAO,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,eAAO,MAAM,KAAK,GAAI,4DAOnB,UAAU,4CAqBZ,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { cn } from "../../utils/cn";
|
|
4
|
+
import styles from "./Arrow.module.css";
|
|
5
|
+
export const Arrow = ({ className, variant = "middle", active = false, height = 40, children, ...props }) => {
|
|
6
|
+
const clipMap = {
|
|
7
|
+
start: "polygon(0% 0%, calc(100% - 20px) 0%, 100% 50%, calc(100% - 20px) 100%, 0% 100%)",
|
|
8
|
+
middle: "polygon(0% 0%, calc(100% - 20px) 0%, 100% 50%, calc(100% - 20px) 100%, 0% 100%, 20px 50%)",
|
|
9
|
+
end: "polygon(0% 0%, 100% 0%, 100% 50%, 100% 100%, 0% 100%, 20px 50%)",
|
|
10
|
+
};
|
|
11
|
+
return (_jsx("div", { ...props, className: cn(styles.root, className), style: { height }, children: _jsx("div", { className: cn(styles.arrow, active && styles.active), style: { clipPath: clipMap[variant], height }, children: children }) }));
|
|
12
|
+
};
|
|
@@ -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,7 @@
|
|
|
1
|
+
import type React from "react";
|
|
2
|
+
export type ArrowsProps = React.JSX.IntrinsicElements["div"] & {
|
|
3
|
+
arrows: string[];
|
|
4
|
+
activeIndex: number;
|
|
5
|
+
};
|
|
6
|
+
export declare const Arrows: ({ className, arrows, activeIndex }: ArrowsProps) => import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
//# sourceMappingURL=Arrows.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Arrows.d.ts","sourceRoot":"","sources":["../../../src/components/Arrows/Arrows.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,MAAM,MAAM,WAAW,GAAG,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,KAAK,CAAC,GAAG;IAC7D,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,eAAO,MAAM,MAAM,GAAI,oCAAoC,WAAW,4CAarE,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import clsx from "clsx";
|
|
4
|
+
import { Arrow } from "../Arrow/Arrow";
|
|
5
|
+
import styles from "./Arrows.module.css";
|
|
6
|
+
export const Arrows = ({ className, arrows, activeIndex }) => (_jsx("div", { className: clsx(styles.root, className), children: arrows.map((arrow, index) => (_jsx(Arrow, { className: clsx(index === activeIndex && styles.active), active: index === activeIndex, variant: index === 0 ? "start" : index === arrows.length - 1 ? "end" : "middle", children: arrow }, arrow))) }));
|
|
@@ -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,9 @@
|
|
|
1
|
+
import type { MouseEventHandler, ReactNode } from "react";
|
|
2
|
+
export interface BackLinkProps {
|
|
3
|
+
text?: ReactNode;
|
|
4
|
+
href?: string;
|
|
5
|
+
onClick?: MouseEventHandler<HTMLAnchorElement>;
|
|
6
|
+
className?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function BackLink({ text, href, onClick, className, }: BackLinkProps): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
//# sourceMappingURL=BackLink.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BackLink.d.ts","sourceRoot":"","sources":["../../src/components/BackLink.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAG1D,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,iBAAiB,CAAC,iBAAiB,CAAC,CAAC;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,QAAQ,CAAC,EACvB,IAAa,EACb,IAAU,EACV,OAAO,EACP,SAAS,GACV,EAAE,aAAa,2CAUf"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import clsx from "clsx";
|
|
4
|
+
export function BackLink({ text = "Back", href = "/", onClick, className, }) {
|
|
5
|
+
return (_jsx("a", { href: href, onClick: onClick, className: clsx("govuk-back-link", className), children: text }));
|
|
6
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { JSX, ReactNode } from "react";
|
|
2
|
+
type Props = JSX.IntrinsicElements["button"] & {
|
|
3
|
+
children: ReactNode;
|
|
4
|
+
variant?: "primary" | "secondary" | "warning";
|
|
5
|
+
};
|
|
6
|
+
export declare const Button: ({ variant, className, ...props }: Props) => import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=Button.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../../src/components/Button.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAE5C,KAAK,KAAK,GAAG,GAAG,CAAC,iBAAiB,CAAC,QAAQ,CAAC,GAAG;IAC7C,QAAQ,EAAE,SAAS,CAAC;IACpB,OAAO,CAAC,EAAE,SAAS,GAAG,WAAW,GAAG,SAAS,CAAC;CAC/C,CAAC;AAEF,eAAO,MAAM,MAAM,GAAI,kCAA8C,KAAK,4CAOzE,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import clsx from "clsx";
|
|
4
|
+
export const Button = ({ variant = "primary", className, ...props }) => (_jsx("button", { className: clsx("govuk-button", `govuk-button--${variant}`, className), "aria-disabled": props.disabled, "data-module": "govuk-button", ...props }));
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
export type ButtonGroupProps = React.JSX.IntrinsicElements["div"] & {
|
|
3
|
+
children: ReactNode;
|
|
4
|
+
};
|
|
5
|
+
export declare const ButtonGroup: ({ className, children, ...props }: ButtonGroupProps) => React.JSX.Element;
|
|
6
|
+
//# sourceMappingURL=ButtonGroup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ButtonGroup.d.ts","sourceRoot":"","sources":["../../src/components/ButtonGroup.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,MAAM,gBAAgB,GAAG,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,KAAK,CAAC,GAAG;IAClE,QAAQ,EAAE,SAAS,CAAC;CACrB,CAAC;AAEF,eAAO,MAAM,WAAW,GAAI,mCAAmC,gBAAgB,KAAG,KAAK,CAAC,GAAG,CAAC,OAM3F,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import clsx from "clsx";
|
|
4
|
+
export const ButtonGroup = ({ className, children, ...props }) => {
|
|
5
|
+
return (_jsx("div", { className: clsx("govuk-button-group", className), ...props, children: children }));
|
|
6
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export declare 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
|
+
export type BackgroundType = "default" | "light" | "muted" | "white";
|
|
14
|
+
export declare enum BackgroundColours {
|
|
15
|
+
transparent = "transparent",
|
|
16
|
+
light = "#f8f8f8",
|
|
17
|
+
muted = "#eef1f5",
|
|
18
|
+
white = "#ffffff"
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=Colours.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Colours.d.ts","sourceRoot":"","sources":["../../src/components/Colours.tsx"],"names":[],"mappings":"AAAA,oBAAY,UAAU;IACpB,IAAI,oBAAoB;IACxB,KAAK,qBAAqB;IAC1B,SAAS,yBAAyB;IAClC,IAAI,oBAAoB;IACxB,SAAS,0BAA0B;IACnC,MAAM,sBAAsB;IAC5B,IAAI,oBAAoB;IACxB,GAAG,mBAAmB;IACtB,MAAM,sBAAsB;IAC5B,MAAM,sBAAsB;CAC7B;AAED,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;AACrE,oBAAY,iBAAiB;IAC3B,WAAW,gBAAgB;IAC3B,KAAK,YAAY;IACjB,KAAK,YAAY;IACjB,KAAK,YAAY;CAClB"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export var TagColours;
|
|
2
|
+
(function (TagColours) {
|
|
3
|
+
TagColours["Grey"] = "govuk-tag--grey";
|
|
4
|
+
TagColours["Green"] = "govuk-tag--green";
|
|
5
|
+
TagColours["Turquoise"] = "govuk-tag--turquoise";
|
|
6
|
+
TagColours["Blue"] = "govuk-tag--blue";
|
|
7
|
+
TagColours["LightBlue"] = "govuk-tag--light-blue";
|
|
8
|
+
TagColours["Purple"] = "govuk-tag--purple";
|
|
9
|
+
TagColours["Pink"] = "govuk-tag--pink";
|
|
10
|
+
TagColours["Red"] = "govuk-tag--red";
|
|
11
|
+
TagColours["Orange"] = "govuk-tag--orange";
|
|
12
|
+
TagColours["Yellow"] = "govuk-tag--yellow";
|
|
13
|
+
})(TagColours || (TagColours = {}));
|
|
14
|
+
export var BackgroundColours;
|
|
15
|
+
(function (BackgroundColours) {
|
|
16
|
+
BackgroundColours["transparent"] = "transparent";
|
|
17
|
+
BackgroundColours["light"] = "#f8f8f8";
|
|
18
|
+
BackgroundColours["muted"] = "#eef1f5";
|
|
19
|
+
BackgroundColours["white"] = "#ffffff";
|
|
20
|
+
})(BackgroundColours || (BackgroundColours = {}));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LoadingSpinner.d.ts","sourceRoot":"","sources":["../../../src/components/LoadingSpinner/LoadingSpinner.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAI3C,UAAU,mBAAmB;IAC3B,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAGD,eAAO,MAAM,cAAc,EAAE,EAAE,CAAC,mBAAmB,CAKlD,CAAC;AAEF,eAAe,cAAc,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import styles from "./LoadingSpinner.module.css";
|
|
4
|
+
// https://design.homeoffice.gov.uk/design-system/components?name=Loading%20spinner
|
|
5
|
+
export const LoadingSpinner = ({ children }) => (_jsxs("div", { className: styles["hods-loading-spinner"], role: "status", "aria-live": "polite", "aria-busy": "true", children: [_jsx("div", { className: styles["hods-loading-spinner__spinner"], "aria-hidden": "true" }), children && _jsx("div", { className: styles["hods-loading-spinner__text"], children: children })] }));
|
|
6
|
+
export default LoadingSpinner;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
.hods-loading-spinner {
|
|
2
|
+
position: relative;
|
|
3
|
+
display: flex;
|
|
4
|
+
flex-direction: column;
|
|
5
|
+
align-items: center;
|
|
6
|
+
justify-content: center;
|
|
7
|
+
min-height: 100px;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.hods-loading-spinner__spinner {
|
|
11
|
+
border: 8px solid #dee0e2;
|
|
12
|
+
border-top-color: #005ea5; /* govuk blue */
|
|
13
|
+
border-radius: 50%;
|
|
14
|
+
width: 60px;
|
|
15
|
+
height: 60px;
|
|
16
|
+
animation: hods-spin 1s linear infinite;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.hods-loading-spinner__text {
|
|
20
|
+
margin-top: 0.75rem;
|
|
21
|
+
font-size: 1rem;
|
|
22
|
+
color: #0b0c0c; /* govuk body text */
|
|
23
|
+
text-align: center;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@keyframes hods-spin {
|
|
27
|
+
0% {
|
|
28
|
+
transform: rotate(0deg);
|
|
29
|
+
}
|
|
30
|
+
100% {
|
|
31
|
+
transform: rotate(360deg);
|
|
32
|
+
}
|
|
33
|
+
}
|