@uktrade/react-component-library 0.18.2 → 0.20.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.
@@ -1,10 +1,9 @@
1
1
  interface ApiBoundaryProps {
2
- isLoading: boolean;
3
- isError: boolean;
4
- error?: unknown;
5
- onRetry?: () => void;
2
+ isLoading?: boolean;
3
+ isError?: boolean;
4
+ error?: React.ReactNode | Error | null;
6
5
  children: React.ReactNode;
7
6
  }
8
- export declare const ApiBoundary: ({ isLoading, isError, error, onRetry, children, }: ApiBoundaryProps) => import("react/jsx-runtime").JSX.Element;
7
+ export declare function ApiBoundary({ isLoading, isError, error, children }: ApiBoundaryProps): import("react/jsx-runtime").JSX.Element;
9
8
  export {};
10
9
  //# sourceMappingURL=ApiBoundary.d.ts.map
@@ -1 +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,4CAwBlB,CAAC"}
1
+ {"version":3,"file":"ApiBoundary.d.ts","sourceRoot":"","sources":["../../../src/components/ApiBoundary/ApiBoundary.tsx"],"names":[],"mappings":"AAIA,UAAU,gBAAgB;IACxB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,GAAG,KAAK,GAAG,IAAI,CAAC;IACvC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED,wBAAgB,WAAW,CAAC,EAC1B,SAAS,EACT,OAAe,EACf,KAAK,EACL,QAAQ,EACT,EAAE,gBAAgB,2CAalB"}
@@ -1,7 +1,16 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- // import { LoadingBox } from "govuk-react";
1
+ "use client";
2
+ import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
3
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) }), onRetry && (_jsx(Button, { variant: "warning", onClick: onRetry, children: "Retry" }))] })] }))] }));
4
+ export function ApiBoundary({ isLoading, isError = false, error, children }) {
5
+ if (isLoading) {
6
+ return _jsx(LoadingSpinner, {});
7
+ }
8
+ if (isError) {
9
+ if (error instanceof Error) {
10
+ return _jsx("p", { children: error.message });
11
+ }
12
+ return _jsx(_Fragment, { children: error });
13
+ }
14
+ return _jsx(_Fragment, { children: children });
15
+ }
16
+ ;
@@ -0,0 +1,23 @@
1
+ import type { JSX, ReactNode } from "react";
2
+ type LabelAs = "h1" | "h2" | "h3" | "h4";
3
+ type LabelSize = "s" | "m" | "l" | "xl";
4
+ interface RadioItem {
5
+ value: string;
6
+ label: ReactNode;
7
+ hint?: ReactNode;
8
+ }
9
+ interface RadioGroupProps extends Omit<JSX.IntrinsicElements["input"], "id" | "type"> {
10
+ id: string;
11
+ name: string;
12
+ label: ReactNode;
13
+ hint?: ReactNode;
14
+ error?: string;
15
+ items: RadioItem[];
16
+ labelAs?: LabelAs;
17
+ labelSize?: LabelSize;
18
+ className?: string;
19
+ inline?: boolean;
20
+ }
21
+ export declare const RadioGroup: ({ id, name, label, hint, error, items, labelAs, labelSize, className, inline, ...props }: RadioGroupProps) => import("react/jsx-runtime").JSX.Element;
22
+ export {};
23
+ //# sourceMappingURL=RadioInput.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RadioInput.d.ts","sourceRoot":"","sources":["../../../../src/components/Inputs/RadioInput/RadioInput.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,GAAG,EAAE,SAAS,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,SAAS;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,SAAS,CAAC;IACjB,IAAI,CAAC,EAAE,SAAS,CAAC;CACpB;AAED,UAAU,eACN,SAAQ,IAAI,CAAC,GAAG,CAAC,iBAAiB,CAAC,OAAO,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;IAC3D,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,SAAS,CAAC;IACjB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,eAAO,MAAM,UAAU,GAAI,0FAYxB,eAAe,4CAwGjB,CAAC"}
@@ -0,0 +1,27 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import clsx from "clsx";
4
+ import { createElement } from "react";
5
+ export const RadioGroup = ({ id, name, label, hint, error, items, labelAs, labelSize = "l", className, inline = false, ...props }) => {
6
+ const hasError = Boolean(error);
7
+ const hintId = hint ? `${id}-hint` : undefined;
8
+ const errorId = hasError ? `${id}-error` : undefined;
9
+ const ariaDescribedBy = [hintId, errorId].filter(Boolean).join(" ") || undefined;
10
+ const legendElement = (_jsx("legend", { className: clsx("govuk-fieldset__legend", `govuk-fieldset__legend--${labelSize}`), children: labelAs
11
+ ? createElement(labelAs, { className: "govuk-fieldset__heading" }, label)
12
+ : _jsx("span", { className: "govuk-fieldset__heading", children: label }) }));
13
+ return (_jsx("div", { className: clsx("govuk-form-group", {
14
+ "govuk-form-group--error": hasError,
15
+ }), children: _jsxs("fieldset", { className: "govuk-fieldset", "aria-describedby": ariaDescribedBy, children: [legendElement, 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("div", { className: clsx("govuk-radios", {
16
+ "govuk-radios--inline": inline,
17
+ "govuk-radios--error": hasError,
18
+ }, className), "data-module": "govuk-radios", children: items.map((item, index) => {
19
+ const itemId = `${id}-${index}`;
20
+ const itemHintId = item.hint ? `${itemId}-hint` : undefined;
21
+ const describedBy = [
22
+ ariaDescribedBy, // group hint + group error
23
+ itemHintId // per-item hint
24
+ ].filter(Boolean).join(" ") || undefined;
25
+ return (_jsxs("div", { className: "govuk-radios__item", children: [_jsx("input", { className: "govuk-radios__input", id: itemId, name: name, type: "radio", value: item.value, "aria-describedby": describedBy, ...props }), _jsx("label", { className: "govuk-label govuk-radios__label", htmlFor: itemId, children: item.label }), item.hint && (_jsx("div", { id: itemHintId, className: "govuk-hint govuk-radios__hint", children: item.hint }))] }, item.value));
26
+ }) })] }) }));
27
+ };
@@ -0,0 +1,16 @@
1
+ import type { ReactNode, JSX } from "react";
2
+ type LabelAs = "h1" | "h2" | "h3" | "h4";
3
+ type LabelSize = "s" | "m" | "l" | "xl";
4
+ interface TextareaInputProps extends Omit<JSX.IntrinsicElements["textarea"], "id"> {
5
+ id: string;
6
+ label: ReactNode;
7
+ hint?: ReactNode;
8
+ error?: string;
9
+ labelAs?: LabelAs;
10
+ labelSize?: LabelSize;
11
+ rows?: number;
12
+ className?: string;
13
+ }
14
+ export declare const TextAreaInput: ({ id, label, hint, error, labelAs, labelSize, rows, className, ...props }: TextareaInputProps) => import("react/jsx-runtime").JSX.Element;
15
+ export {};
16
+ //# sourceMappingURL=TextAreaInput.d.ts.map
@@ -0,0 +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,4CA6DpB,CAAC"}
@@ -0,0 +1,21 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
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 }) => {
6
+ const hasError = Boolean(error);
7
+ const hintId = hint ? `${id}-hint` : undefined;
8
+ const errorId = hasError ? `${id}-error` : undefined;
9
+ const ariaDescribedBy = [
10
+ hintId,
11
+ errorId
12
+ ].filter(Boolean).join(" ") || undefined;
13
+ const labelElement = (_jsx("label", { htmlFor: id, className: clsx("govuk-label", {
14
+ [`govuk-label--${labelSize}`]: true,
15
+ }), children: label }));
16
+ return (_jsxs("div", { className: clsx("govuk-form-group", {
17
+ "govuk-form-group--error": hasError,
18
+ }), children: [labelAs
19
+ ? 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 })] }));
21
+ };
@@ -1,4 +1,6 @@
1
1
  export * from "./TextInput/TextInput";
2
2
  export * from "./CheckBoxesInput/CheckBoxGroupInput";
3
3
  export * from "./SelectInput/SelectInput";
4
+ export * from "./TextAreaInput/TextAreaInput";
5
+ export * from "./RadioInput/RadioInput";
4
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Inputs/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,sCAAsC,CAAC;AACrD,cAAc,2BAA2B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Inputs/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,sCAAsC,CAAC;AACrD,cAAc,2BAA2B,CAAC;AAC1C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,yBAAyB,CAAC"}
@@ -1,3 +1,5 @@
1
1
  export * from "./TextInput/TextInput";
2
2
  export * from "./CheckBoxesInput/CheckBoxGroupInput";
3
3
  export * from "./SelectInput/SelectInput";
4
+ export * from "./TextAreaInput/TextAreaInput";
5
+ export * from "./RadioInput/RadioInput";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uktrade/react-component-library",
3
- "version": "0.18.2",
3
+ "version": "0.20.1",
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",
@@ -54,17 +54,17 @@
54
54
  "@testing-library/user-event": "^14.6.1",
55
55
  "@types/react": "^19.2.9",
56
56
  "@types/react-dom": "^19.2.3",
57
- "@typescript-eslint/eslint-plugin": "^8.53.1",
58
- "@typescript-eslint/parser": "^8.53.1",
57
+ "@typescript-eslint/eslint-plugin": "^8.59.0",
58
+ "@typescript-eslint/parser": "^8.59.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
- "globals": "^17.2.0",
63
+ "globals": "^17.5.0",
64
64
  "jsdom": "^27.4.0",
65
- "openapi-typescript": "^7.10.1",
65
+ "openapi-typescript": "^7.13.0",
66
66
  "typescript": "^5.9.3",
67
- "typescript-eslint": "^8.53.1",
67
+ "typescript-eslint": "^8.59.0",
68
68
  "vitest": "^4.0.18"
69
69
  },
70
70
  "engines": {
@@ -1,45 +1,30 @@
1
- // import { LoadingBox } from "govuk-react";
1
+ "use client"
2
+
2
3
  import { LoadingSpinner } from "../LoadingSpinner/LoadingSpinner";
3
- import styles from "./ApiBoundary.module.css";
4
- import { Button } from "../Button";
5
4
 
6
5
  interface ApiBoundaryProps {
7
- isLoading: boolean;
8
- isError: boolean;
9
- error?: unknown;
10
- onRetry?: () => void;
6
+ isLoading?: boolean;
7
+ isError?: boolean;
8
+ error?: React.ReactNode | Error | null;
11
9
  children: React.ReactNode;
12
10
  }
13
11
 
14
- /* Boundary for API-related states: loading, success, and error */
15
- export const ApiBoundary = ({
12
+ export function ApiBoundary({
16
13
  isLoading,
17
- isError,
14
+ isError = false,
18
15
  error,
19
- onRetry,
20
- children,
21
- }: ApiBoundaryProps) => (
22
- <div className={styles.root} aria-live="polite">
23
- {isLoading && <LoadingSpinner />}
16
+ children
17
+ }: ApiBoundaryProps) {
18
+ if (isLoading) {
19
+ return <LoadingSpinner />;
20
+ }
24
21
 
25
- {!isLoading && !isError && children}
22
+ if (isError) {
23
+ if (error instanceof Error) {
24
+ return <p>{error.message}</p>;
25
+ }
26
+ return <>{error}</>;
27
+ }
26
28
 
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
- {onRetry && (
37
- <Button variant="warning" onClick={onRetry}>
38
- Retry
39
- </Button>
40
- )}
41
- </section>
42
- </>
43
- )}
44
- </div>
45
- );
29
+ return <>{children}</>;
30
+ };
@@ -0,0 +1,146 @@
1
+ "use client";
2
+
3
+ import clsx from "clsx";
4
+ import type { JSX, ReactNode } from "react";
5
+ import { createElement } from "react";
6
+
7
+ type LabelAs = "h1" | "h2" | "h3" | "h4";
8
+ type LabelSize = "s" | "m" | "l" | "xl";
9
+
10
+ interface RadioItem {
11
+ value: string;
12
+ label: ReactNode;
13
+ hint?: ReactNode;
14
+ }
15
+
16
+ interface RadioGroupProps
17
+ extends Omit<JSX.IntrinsicElements["input"], "id" | "type"> {
18
+ id: string;
19
+ name: string;
20
+ label: ReactNode;
21
+ hint?: ReactNode;
22
+ error?: string;
23
+ items: RadioItem[];
24
+ labelAs?: LabelAs;
25
+ labelSize?: LabelSize;
26
+ className?: string;
27
+ inline?: boolean;
28
+ }
29
+
30
+ export const RadioGroup = ({
31
+ id,
32
+ name,
33
+ label,
34
+ hint,
35
+ error,
36
+ items,
37
+ labelAs,
38
+ labelSize = "l",
39
+ className,
40
+ inline = false,
41
+ ...props
42
+ }: RadioGroupProps) => {
43
+ const hasError = Boolean(error);
44
+
45
+ const hintId = hint ? `${id}-hint` : undefined;
46
+ const errorId = hasError ? `${id}-error` : undefined;
47
+
48
+ const ariaDescribedBy =
49
+ [hintId, errorId].filter(Boolean).join(" ") || undefined;
50
+
51
+ const legendElement = (
52
+ <legend
53
+ className={clsx(
54
+ "govuk-fieldset__legend",
55
+ `govuk-fieldset__legend--${labelSize}`
56
+ )}
57
+ >
58
+ {labelAs
59
+ ? createElement(
60
+ labelAs,
61
+ { className: "govuk-fieldset__heading" },
62
+ label
63
+ )
64
+ : <span className="govuk-fieldset__heading">{label}</span>}
65
+ </legend>
66
+ );
67
+
68
+ return (
69
+ <div
70
+ className={clsx("govuk-form-group", {
71
+ "govuk-form-group--error": hasError,
72
+ })}
73
+ >
74
+ <fieldset
75
+ className="govuk-fieldset"
76
+ aria-describedby={ariaDescribedBy}
77
+ >
78
+ {legendElement}
79
+
80
+ {hint && (
81
+ <div id={hintId} className="govuk-hint">
82
+ {hint}
83
+ </div>
84
+ )}
85
+
86
+ {hasError && (
87
+ <p id={errorId} className="govuk-error-message">
88
+ <span className="govuk-visually-hidden">Error:</span>{" "}
89
+ {error}
90
+ </p>
91
+ )}
92
+
93
+ <div
94
+ className={clsx(
95
+ "govuk-radios",
96
+ {
97
+ "govuk-radios--inline": inline,
98
+ "govuk-radios--error": hasError,
99
+ },
100
+ className
101
+ )}
102
+ data-module="govuk-radios"
103
+ >
104
+ {items.map((item, index) => {
105
+ const itemId = `${id}-${index}`;
106
+ const itemHintId = item.hint ? `${itemId}-hint` : undefined;
107
+ const describedBy = [
108
+ ariaDescribedBy, // group hint + group error
109
+ itemHintId // per-item hint
110
+ ].filter(Boolean).join(" ") || undefined;
111
+
112
+ return (
113
+ <div className="govuk-radios__item" key={item.value}>
114
+ <input
115
+ className="govuk-radios__input"
116
+ id={itemId}
117
+ name={name}
118
+ type="radio"
119
+ value={item.value}
120
+ aria-describedby={describedBy}
121
+ {...props}
122
+ />
123
+
124
+ <label
125
+ className="govuk-label govuk-radios__label"
126
+ htmlFor={itemId}
127
+ >
128
+ {item.label}
129
+ </label>
130
+
131
+ {item.hint && (
132
+ <div
133
+ id={itemHintId}
134
+ className="govuk-hint govuk-radios__hint"
135
+ >
136
+ {item.hint}
137
+ </div>
138
+ )}
139
+ </div>
140
+ );
141
+ })}
142
+ </div>
143
+ </fieldset>
144
+ </div>
145
+ );
146
+ };
@@ -0,0 +1,93 @@
1
+ "use client";
2
+
3
+ import clsx from "clsx";
4
+ import type { ReactNode, JSX } from "react";
5
+ import { createElement } from "react";
6
+
7
+ type LabelAs = "h1" | "h2" | "h3" | "h4";
8
+ type LabelSize = "s" | "m" | "l" | "xl";
9
+
10
+ interface TextareaInputProps
11
+ extends Omit<JSX.IntrinsicElements["textarea"], "id"> {
12
+ id: string;
13
+ label: ReactNode;
14
+ hint?: ReactNode;
15
+ error?: string;
16
+ labelAs?: LabelAs;
17
+ labelSize?: LabelSize;
18
+ rows?: number;
19
+ className?: string;
20
+ }
21
+
22
+ export const TextAreaInput = ({
23
+ id,
24
+ label,
25
+ hint,
26
+ error,
27
+ labelAs,
28
+ labelSize = "l",
29
+ rows = 5,
30
+ className,
31
+ ...props
32
+ }: TextareaInputProps) => {
33
+ const hasError = Boolean(error);
34
+
35
+ const hintId = hint ? `${id}-hint` : undefined;
36
+ const errorId = hasError ? `${id}-error` : undefined;
37
+
38
+ const ariaDescribedBy = [
39
+ hintId,
40
+ errorId
41
+ ].filter(Boolean).join(" ") || undefined;
42
+
43
+ const labelElement = (
44
+ <label
45
+ htmlFor={id}
46
+ className={clsx("govuk-label", {
47
+ [`govuk-label--${labelSize}`]: true,
48
+ })}
49
+ >
50
+ {label}
51
+ </label>
52
+ );
53
+
54
+ return (
55
+ <div
56
+ className={clsx("govuk-form-group", {
57
+ "govuk-form-group--error": hasError,
58
+ })}
59
+ >
60
+ {labelAs
61
+ ? createElement(
62
+ labelAs,
63
+ { className: "govuk-label-wrapper" },
64
+ labelElement
65
+ )
66
+ : labelElement}
67
+
68
+ {hint && (
69
+ <div id={hintId} className="govuk-hint">
70
+ {hint}
71
+ </div>
72
+ )}
73
+
74
+ {hasError && (
75
+ <p id={errorId} className="govuk-error-message">
76
+ <span className="govuk-visually-hidden">Error:</span> {error}
77
+ </p>
78
+ )}
79
+
80
+ <textarea
81
+ id={id}
82
+ rows={rows}
83
+ className={clsx(
84
+ "govuk-textarea",
85
+ { "govuk-textarea--error": hasError },
86
+ className
87
+ )}
88
+ aria-describedby={ariaDescribedBy}
89
+ {...props}
90
+ />
91
+ </div>
92
+ );
93
+ };
@@ -1,3 +1,5 @@
1
1
  export * from "./TextInput/TextInput";
2
2
  export * from "./CheckBoxesInput/CheckBoxGroupInput";
3
- export * from "./SelectInput/SelectInput";
3
+ export * from "./SelectInput/SelectInput";
4
+ export * from "./TextAreaInput/TextAreaInput";
5
+ export * from "./RadioInput/RadioInput";
@@ -1,30 +0,0 @@
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
- }
@@ -1,30 +0,0 @@
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
- }
File without changes