@uktrade/react-component-library 0.22.11 → 0.22.13
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/dist/components/ApiQuery/ApiCreateHooks.d.ts.map +1 -1
- package/dist/components/ApiQuery/ApiCreateHooks.js +15 -36
- package/dist/components/Inputs/TextAreaInput/TextAreaInput.d.ts +2 -1
- package/dist/components/Inputs/TextAreaInput/TextAreaInput.d.ts.map +1 -1
- package/dist/components/Inputs/TextAreaInput/TextAreaInput.js +17 -4
- package/package.json +3 -3
- package/src/components/ApiQuery/ApiCreateHooks.tsx +27 -30
- package/src/components/Inputs/TextAreaInput/TextAreaInput.tsx +38 -2
|
@@ -1 +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;
|
|
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;AAqBpD,wBAAgB,cAAc,CAAC,KAAK,SAAS,EAAE,EAC7C,MAAM,EAAE,UAAU,CAAC,OAAO,eAAe,CAAC,KAAK,CAAC,CAAC;UAQzC,CAAC,SAAS,eAAe,CAAC,KAAK,EAAE,KAAK,CAAC,QACrC,CAAC,UACC,GAAG;;;;;;;;;;WAQN,CAAC,SAAS,eAAe,CAAC,KAAK,EAAE,MAAM,CAAC,QACvC,CAAC,UACC,GAAG;;;;;;;;;;mBAUE,CAAC,SAAS,eAAe,CAAC,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC;;;;;;;;;;kBAKlD,CAAC,SAAS,eAAe,CAAC,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC;;;;;;;;;;oBAK9C,CAAC,SAAS,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC;;;;;;;;;;qBAKjD,CAAC,SAAS,eAAe,CAAC,KAAK,EAAE,QAAQ,CAAC,QAAQ,CAAC;;;;;;;;;;EAKvE"}
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { createApiClient } from "./ApiCreateClient";
|
|
3
3
|
import { useApi, useApiMutation } from "./ApiProvider";
|
|
4
|
+
function unwrap(res) {
|
|
5
|
+
if (res.error) {
|
|
6
|
+
throw Object.assign(res.error, {
|
|
7
|
+
status: res.response.status,
|
|
8
|
+
response: res.response,
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
return res.data;
|
|
12
|
+
}
|
|
4
13
|
// API hook factory that converts a typed OpenAPI client into React hooks (`useApi` and `useApiMutation`) that the UI can use.
|
|
5
14
|
// Provides a simple interface for making API calls and handling loading and error states in your React components.
|
|
6
15
|
export function createApiHooks(client) {
|
|
@@ -10,53 +19,23 @@ export function createApiHooks(client) {
|
|
|
10
19
|
// Using useQuery
|
|
11
20
|
return {
|
|
12
21
|
get: (path, input) => {
|
|
13
|
-
return useApi(["get", path, JSON.stringify(input ?? {})], async () =>
|
|
14
|
-
const res = await client.GET(path, input);
|
|
15
|
-
if (res.error)
|
|
16
|
-
throw res.error;
|
|
17
|
-
return res.data;
|
|
18
|
-
});
|
|
22
|
+
return useApi(["get", path, JSON.stringify(input ?? {})], async () => unwrap(await client.GET(path, input)));
|
|
19
23
|
},
|
|
20
24
|
post: (path, input) => {
|
|
21
|
-
return useApi(["post", path, JSON.stringify(input ?? {})], async () =>
|
|
22
|
-
const res = await client.POST(path, input);
|
|
23
|
-
if (res.error)
|
|
24
|
-
throw res.error;
|
|
25
|
-
return res.data;
|
|
26
|
-
});
|
|
25
|
+
return useApi(["post", path, JSON.stringify(input ?? {})], async () => unwrap(await client.POST(path, input)));
|
|
27
26
|
},
|
|
28
27
|
// Using useMutation
|
|
29
28
|
postMutation: (path) => {
|
|
30
|
-
return useApiMutation(async (input) =>
|
|
31
|
-
const res = await client.POST(path, input);
|
|
32
|
-
if (res.error)
|
|
33
|
-
throw res.error;
|
|
34
|
-
return res.data;
|
|
35
|
-
});
|
|
29
|
+
return useApiMutation(async (input) => unwrap(await client.POST(path, input)));
|
|
36
30
|
},
|
|
37
31
|
putMutation: (path) => {
|
|
38
|
-
return useApiMutation(async (input) =>
|
|
39
|
-
const res = await client.PUT(path, input);
|
|
40
|
-
if (res.error)
|
|
41
|
-
throw res.error;
|
|
42
|
-
return res.data;
|
|
43
|
-
});
|
|
32
|
+
return useApiMutation(async (input) => unwrap(await client.PUT(path, input)));
|
|
44
33
|
},
|
|
45
34
|
patchMutation: (path) => {
|
|
46
|
-
return useApiMutation(async (input) =>
|
|
47
|
-
const res = await client.PATCH(path, input);
|
|
48
|
-
if (res.error)
|
|
49
|
-
throw res.error;
|
|
50
|
-
return res.data;
|
|
51
|
-
});
|
|
35
|
+
return useApiMutation(async (input) => unwrap(await client.PATCH(path, input)));
|
|
52
36
|
},
|
|
53
37
|
deleteMutation: (path) => {
|
|
54
|
-
return useApiMutation(async (input) =>
|
|
55
|
-
const res = await client.DELETE(path, input);
|
|
56
|
-
if (res.error)
|
|
57
|
-
throw res.error;
|
|
58
|
-
return res.data;
|
|
59
|
-
});
|
|
38
|
+
return useApiMutation(async (input) => unwrap(await client.DELETE(path, input)));
|
|
60
39
|
},
|
|
61
40
|
};
|
|
62
41
|
}
|
|
@@ -10,7 +10,8 @@ interface TextareaInputProps extends Omit<JSX.IntrinsicElements["textarea"], "id
|
|
|
10
10
|
labelSize?: LabelSize;
|
|
11
11
|
rows?: number;
|
|
12
12
|
className?: string;
|
|
13
|
+
characterLimit?: number;
|
|
13
14
|
}
|
|
14
|
-
export declare const TextAreaInput: ({ id, label, hint, error, labelAs, labelSize, rows, className, ...props }: TextareaInputProps) => JSX.Element;
|
|
15
|
+
export declare const TextAreaInput: ({ id, label, hint, error, labelAs, labelSize, rows, className, characterLimit, ...props }: TextareaInputProps) => JSX.Element;
|
|
15
16
|
export {};
|
|
16
17
|
//# sourceMappingURL=TextAreaInput.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TextAreaInput.d.ts","sourceRoot":"","sources":["../../../../src/components/Inputs/TextAreaInput/TextAreaInput.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAG5C,KAAK,OAAO,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AACzC,KAAK,SAAS,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAAI,CAAC;AAExC,UAAU,kBACN,SAAQ,IAAI,CAAC,GAAG,CAAC,iBAAiB,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC;IACrD,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,SAAS,CAAC;IACjB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"TextAreaInput.d.ts","sourceRoot":"","sources":["../../../../src/components/Inputs/TextAreaInput/TextAreaInput.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAG5C,KAAK,OAAO,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AACzC,KAAK,SAAS,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAAI,CAAC;AAExC,UAAU,kBACN,SAAQ,IAAI,CAAC,GAAG,CAAC,iBAAiB,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC;IACrD,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,SAAS,CAAC;IACjB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,eAAO,MAAM,aAAa,GAAI,2FAW3B,kBAAkB,gBA+FpB,CAAC"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import clsx from "clsx";
|
|
4
|
-
import { createElement } from "react";
|
|
5
|
-
export const TextAreaInput = ({ id, label, hint, error, labelAs, labelSize = "l", rows = 5, className, ...props }) => {
|
|
4
|
+
import { createElement, useState } from "react";
|
|
5
|
+
export const TextAreaInput = ({ id, label, hint, error, labelAs, labelSize = "l", rows = 5, className, characterLimit, ...props }) => {
|
|
6
6
|
const hasError = Boolean(error);
|
|
7
7
|
const hintId = hint ? `${id}-hint` : undefined;
|
|
8
8
|
const errorId = hasError ? `${id}-error` : undefined;
|
|
@@ -10,12 +10,25 @@ export const TextAreaInput = ({ id, label, hint, error, labelAs, labelSize = "l"
|
|
|
10
10
|
hintId,
|
|
11
11
|
errorId
|
|
12
12
|
].filter(Boolean).join(" ") || undefined;
|
|
13
|
+
const hasLimit = characterLimit !== undefined;
|
|
14
|
+
const [count, setCount] = useState(0);
|
|
13
15
|
const labelElement = (_jsx("label", { htmlFor: id, className: clsx("govuk-label", {
|
|
14
16
|
[`govuk-label--${labelSize}`]: true,
|
|
15
17
|
}), children: label }));
|
|
18
|
+
const remaining = hasLimit ? characterLimit - count : undefined;
|
|
19
|
+
const isOverLimit = remaining !== undefined && remaining < 0;
|
|
20
|
+
const characterMessage = remaining !== undefined
|
|
21
|
+
? (remaining < 0
|
|
22
|
+
? `You have ${Math.abs(remaining)} character${Math.abs(remaining) === 1 ? "" : "s"} too many`
|
|
23
|
+
: `You have ${remaining} character${remaining === 1 ? "" : "s"} remaining`)
|
|
24
|
+
: undefined;
|
|
16
25
|
return (_jsxs("div", { className: clsx("govuk-form-group", {
|
|
17
26
|
"govuk-form-group--error": hasError,
|
|
18
|
-
|
|
27
|
+
"govuk-character-count": hasLimit
|
|
28
|
+
}), ...(hasLimit ? { "data-module": "govuk-character-count", "data-maxlength": characterLimit } : {}), children: [labelAs
|
|
19
29
|
? createElement(labelAs, { className: "govuk-label-wrapper" }, labelElement)
|
|
20
|
-
: labelElement, hint && (_jsx("div", { id: hintId, className: "govuk-hint", children: hint })), hasError && (_jsxs("p", { id: errorId, className: "govuk-error-message", children: [_jsx("span", { className: "govuk-visually-hidden", children: "Error:" }), " ", error] })), _jsx("textarea", { id: id, rows: rows, className: clsx("govuk-textarea", { "govuk-textarea--error": hasError
|
|
30
|
+
: labelElement, hint && (_jsx("div", { id: hintId, className: "govuk-hint", children: hint })), hasError && (_jsxs("p", { id: errorId, className: "govuk-error-message", children: [_jsx("span", { className: "govuk-visually-hidden", children: "Error:" }), " ", error] })), _jsx("textarea", { id: id, rows: rows, className: clsx("govuk-textarea", { "govuk-textarea--error": hasError,
|
|
31
|
+
"govuk-js-character-count": hasLimit }, className), style: isOverLimit ? { borderColor: "#d4351c" } : {}, "aria-describedby": ariaDescribedBy, ...props, onChange: e => {
|
|
32
|
+
setCount(e.target.value.length);
|
|
33
|
+
} }), hasLimit && (_jsx("div", { id: "with-hint-info", className: clsx("govuk-hint govuk-character-count__message", { "govuk-error-message": isOverLimit }), style: isOverLimit ? { color: "#d4351c", fontWeight: "bold" } : {}, children: characterMessage }))] }));
|
|
21
34
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uktrade/react-component-library",
|
|
3
|
-
"version": "0.22.
|
|
3
|
+
"version": "0.22.13",
|
|
4
4
|
"description": "A collection of reusable React components following GOV.UK design patterns.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -55,13 +55,13 @@
|
|
|
55
55
|
"@types/react": "^19.2.9",
|
|
56
56
|
"@types/react-dom": "^19.2.3",
|
|
57
57
|
"@typescript-eslint/eslint-plugin": "^8.59.0",
|
|
58
|
-
"@typescript-eslint/parser": "^8.
|
|
58
|
+
"@typescript-eslint/parser": "^8.62.0",
|
|
59
59
|
"@vitest/coverage-v8": "^4.0.18",
|
|
60
60
|
"@vitest/ui": "^4.0.18",
|
|
61
61
|
"eslint": "^9.39.2",
|
|
62
62
|
"eslint-plugin-react": "^7.37.5",
|
|
63
63
|
"globals": "^17.5.0",
|
|
64
|
-
"jsdom": "^
|
|
64
|
+
"jsdom": "^29.1.1",
|
|
65
65
|
"openapi-typescript": "^7.13.0",
|
|
66
66
|
"typescript": "^5.9.3",
|
|
67
67
|
"typescript-eslint": "^8.59.0",
|
|
@@ -5,6 +5,22 @@ import type { PathsWithMethod } from "openapi-typescript-helpers";
|
|
|
5
5
|
import { createApiClient } from "./ApiCreateClient";
|
|
6
6
|
import { useApi, useApiMutation } from "./ApiProvider";
|
|
7
7
|
|
|
8
|
+
|
|
9
|
+
function unwrap<T>(res: {
|
|
10
|
+
data?: T;
|
|
11
|
+
error?: any;
|
|
12
|
+
response: Response;
|
|
13
|
+
}): T {
|
|
14
|
+
if (res.error) {
|
|
15
|
+
throw Object.assign(res.error, {
|
|
16
|
+
status: res.response.status,
|
|
17
|
+
response: res.response,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return res.data as T;
|
|
22
|
+
}
|
|
23
|
+
|
|
8
24
|
// API hook factory that converts a typed OpenAPI client into React hooks (`useApi` and `useApiMutation`) that the UI can use.
|
|
9
25
|
// Provides a simple interface for making API calls and handling loading and error states in your React components.
|
|
10
26
|
export function createApiHooks<Paths extends {}>(
|
|
@@ -22,11 +38,7 @@ export function createApiHooks<Paths extends {}>(
|
|
|
22
38
|
) => {
|
|
23
39
|
return useApi(
|
|
24
40
|
["get", path, JSON.stringify(input ?? {})],
|
|
25
|
-
async () =>
|
|
26
|
-
const res = await client.GET(path, input);
|
|
27
|
-
if (res.error) throw res.error;
|
|
28
|
-
return res.data;
|
|
29
|
-
}
|
|
41
|
+
async () => unwrap(await client.GET(path, input))
|
|
30
42
|
);
|
|
31
43
|
},
|
|
32
44
|
|
|
@@ -36,45 +48,30 @@ export function createApiHooks<Paths extends {}>(
|
|
|
36
48
|
) => {
|
|
37
49
|
return useApi(
|
|
38
50
|
["post", path, JSON.stringify(input ?? {})],
|
|
39
|
-
async () =>
|
|
40
|
-
|
|
41
|
-
if (res.error) throw res.error;
|
|
42
|
-
return res.data;
|
|
43
|
-
}
|
|
51
|
+
async () =>
|
|
52
|
+
unwrap(await client.POST(path, input))
|
|
44
53
|
);
|
|
45
54
|
},
|
|
46
55
|
|
|
47
56
|
// Using useMutation
|
|
48
57
|
postMutation: <P extends PathsWithMethod<Paths, "post">>(path: P) => {
|
|
49
|
-
return useApiMutation(async (input: any) =>
|
|
50
|
-
|
|
51
|
-
if (res.error) throw res.error;
|
|
52
|
-
return res.data;
|
|
53
|
-
});
|
|
58
|
+
return useApiMutation(async (input: any) =>
|
|
59
|
+
unwrap(await client.POST(path, input)));
|
|
54
60
|
},
|
|
55
61
|
|
|
56
62
|
putMutation: <P extends PathsWithMethod<Paths, "put">>(path: P) => {
|
|
57
|
-
return useApiMutation(async (input: any) =>
|
|
58
|
-
|
|
59
|
-
if (res.error) throw res.error;
|
|
60
|
-
return res.data;
|
|
61
|
-
});
|
|
63
|
+
return useApiMutation(async (input: any) =>
|
|
64
|
+
unwrap(await client.PUT(path, input)));
|
|
62
65
|
},
|
|
63
66
|
|
|
64
67
|
patchMutation: <P extends PathsWithMethod<Paths, "patch">>(path: P) => {
|
|
65
|
-
return useApiMutation(async (input: any)
|
|
66
|
-
|
|
67
|
-
if (res.error) throw res.error;
|
|
68
|
-
return res.data;
|
|
69
|
-
});
|
|
68
|
+
return useApiMutation(async (input: any)=>
|
|
69
|
+
unwrap(await client.PATCH(path, input)));
|
|
70
70
|
},
|
|
71
71
|
|
|
72
72
|
deleteMutation: <P extends PathsWithMethod<Paths, "delete">>(path: P) => {
|
|
73
|
-
return useApiMutation(async (input: any) =>
|
|
74
|
-
|
|
75
|
-
if (res.error) throw res.error;
|
|
76
|
-
return res.data;
|
|
77
|
-
});
|
|
73
|
+
return useApiMutation(async (input: any) =>
|
|
74
|
+
unwrap(await client.DELETE(path, input)));
|
|
78
75
|
},
|
|
79
76
|
};
|
|
80
77
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import clsx from "clsx";
|
|
4
4
|
import type { ReactNode, JSX } from "react";
|
|
5
|
-
import { createElement } from "react";
|
|
5
|
+
import { createElement, useState } from "react";
|
|
6
6
|
|
|
7
7
|
type LabelAs = "h1" | "h2" | "h3" | "h4";
|
|
8
8
|
type LabelSize = "s" | "m" | "l" | "xl";
|
|
@@ -17,6 +17,7 @@ interface TextareaInputProps
|
|
|
17
17
|
labelSize?: LabelSize;
|
|
18
18
|
rows?: number;
|
|
19
19
|
className?: string;
|
|
20
|
+
characterLimit?: number;
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
export const TextAreaInput = ({
|
|
@@ -28,9 +29,11 @@ export const TextAreaInput = ({
|
|
|
28
29
|
labelSize = "l",
|
|
29
30
|
rows = 5,
|
|
30
31
|
className,
|
|
32
|
+
characterLimit,
|
|
31
33
|
...props
|
|
32
34
|
}: TextareaInputProps) => {
|
|
33
35
|
const hasError = Boolean(error);
|
|
36
|
+
|
|
34
37
|
|
|
35
38
|
const hintId = hint ? `${id}-hint` : undefined;
|
|
36
39
|
const errorId = hasError ? `${id}-error` : undefined;
|
|
@@ -40,6 +43,11 @@ export const TextAreaInput = ({
|
|
|
40
43
|
errorId
|
|
41
44
|
].filter(Boolean).join(" ") || undefined;
|
|
42
45
|
|
|
46
|
+
const hasLimit = characterLimit !== undefined;
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
const [count, setCount] = useState(0);
|
|
50
|
+
|
|
43
51
|
const labelElement = (
|
|
44
52
|
<label
|
|
45
53
|
htmlFor={id}
|
|
@@ -51,11 +59,21 @@ export const TextAreaInput = ({
|
|
|
51
59
|
</label>
|
|
52
60
|
);
|
|
53
61
|
|
|
62
|
+
const remaining = hasLimit ? characterLimit - count : undefined;
|
|
63
|
+
const isOverLimit = remaining !== undefined && remaining < 0;
|
|
64
|
+
const characterMessage = remaining !== undefined
|
|
65
|
+
? (remaining < 0
|
|
66
|
+
? `You have ${Math.abs(remaining)} character${Math.abs(remaining) === 1 ? "" : "s"} too many`
|
|
67
|
+
: `You have ${remaining} character${remaining === 1 ? "" : "s"} remaining`)
|
|
68
|
+
: undefined;
|
|
69
|
+
|
|
54
70
|
return (
|
|
55
71
|
<div
|
|
56
72
|
className={clsx("govuk-form-group", {
|
|
57
73
|
"govuk-form-group--error": hasError,
|
|
74
|
+
"govuk-character-count": hasLimit
|
|
58
75
|
})}
|
|
76
|
+
{...(hasLimit ? { "data-module": "govuk-character-count", "data-maxlength": characterLimit } : {})}
|
|
59
77
|
>
|
|
60
78
|
{labelAs
|
|
61
79
|
? createElement(
|
|
@@ -82,12 +100,30 @@ export const TextAreaInput = ({
|
|
|
82
100
|
rows={rows}
|
|
83
101
|
className={clsx(
|
|
84
102
|
"govuk-textarea",
|
|
85
|
-
{ "govuk-textarea--error": hasError
|
|
103
|
+
{ "govuk-textarea--error": hasError ,
|
|
104
|
+
"govuk-js-character-count": hasLimit},
|
|
86
105
|
className
|
|
87
106
|
)}
|
|
107
|
+
style={isOverLimit ? { borderColor: "#d4351c" }: {}}
|
|
88
108
|
aria-describedby={ariaDescribedBy}
|
|
89
109
|
{...props}
|
|
110
|
+
onChange={e => {
|
|
111
|
+
setCount(e.target.value.length);
|
|
112
|
+
}}
|
|
90
113
|
/>
|
|
114
|
+
{hasLimit && (
|
|
115
|
+
<div
|
|
116
|
+
id="with-hint-info"
|
|
117
|
+
className={clsx(
|
|
118
|
+
"govuk-hint govuk-character-count__message",
|
|
119
|
+
{ "govuk-error-message": isOverLimit}
|
|
120
|
+
)}
|
|
121
|
+
style={isOverLimit ? { color: "#d4351c", fontWeight: "bold" }: {}}>
|
|
122
|
+
{characterMessage}
|
|
123
|
+
</div>
|
|
124
|
+
)}
|
|
125
|
+
|
|
126
|
+
|
|
91
127
|
</div>
|
|
92
128
|
);
|
|
93
129
|
};
|