@uktrade/react-component-library 0.22.12 → 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.
@@ -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;CACtB;AAED,eAAO,MAAM,aAAa,GAAI,2EAU3B,kBAAkB,gBA6DpB,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
- }), children: [labelAs
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 }, className), "aria-describedby": ariaDescribedBy, ...props })] }));
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.12",
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",
@@ -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
  };