@coopdigital/react 0.34.0 → 0.36.0
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/Checkbox/Checkbox.d.ts +30 -0
- package/dist/components/Checkbox/Checkbox.js +23 -0
- package/dist/components/Checkbox/CheckboxGroup.d.ts +26 -0
- package/dist/components/Checkbox/CheckboxGroup.js +19 -0
- package/dist/components/Checkbox/index.d.ts +5 -0
- package/dist/components/Field/Field.js +1 -1
- package/dist/components/FieldHint/FieldHint.js +1 -1
- package/dist/components/RadioButton/RadioButton.d.ts +30 -0
- package/dist/components/RadioButton/RadioButton.js +23 -0
- package/dist/components/RadioButton/RadioButtonGroup.d.ts +26 -0
- package/dist/components/RadioButton/RadioButtonGroup.js +19 -0
- package/dist/components/RadioButton/index.d.ts +5 -0
- package/dist/components/SearchBox/SearchBox.d.ts +3 -3
- package/dist/components/SearchBox/SearchBox.js +2 -2
- package/dist/components/{Input/Input.d.ts → TextInput/TextInput.d.ts} +15 -11
- package/dist/components/TextInput/TextInput.js +26 -0
- package/dist/components/TextInput/index.d.ts +4 -0
- package/dist/components/TextInput/index.js +5 -0
- package/dist/components/Textarea/Textarea.d.ts +3 -3
- package/dist/components/Textarea/Textarea.js +7 -7
- package/dist/index.d.ts +3 -1
- package/dist/index.js +5 -1
- package/dist/types/index.d.ts +1 -1
- package/package.json +10 -10
- package/src/components/Checkbox/Checkbox.tsx +81 -0
- package/src/components/Checkbox/CheckboxGroup.tsx +63 -0
- package/src/components/Checkbox/index.ts +6 -0
- package/src/components/Field/Field.tsx +1 -1
- package/src/components/FieldHint/FieldHint.tsx +1 -1
- package/src/components/RadioButton/RadioButton.tsx +79 -0
- package/src/components/RadioButton/RadioButtonGroup.tsx +63 -0
- package/src/components/RadioButton/index.ts +6 -0
- package/src/components/SearchBox/SearchBox.tsx +7 -7
- package/src/components/{Input/Input.tsx → TextInput/TextInput.tsx} +25 -16
- package/src/components/TextInput/index.ts +5 -0
- package/src/components/Textarea/Textarea.tsx +16 -17
- package/src/index.ts +3 -1
- package/src/types/index.ts +1 -1
- package/dist/components/Input/Input.js +0 -26
- package/dist/components/Input/index.d.ts +0 -4
- package/dist/components/Input/index.js +0 -5
- package/src/components/Input/index.ts +0 -5
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { InputHTMLAttributes, JSX } from "react";
|
|
2
|
+
import { FormFieldError, StandardSizes } from "../../../src/types";
|
|
3
|
+
export interface CheckboxProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "size" | "type"> {
|
|
4
|
+
/** **(Optional)** Specify additional CSS classes to be applied to the component. */
|
|
5
|
+
className?: string;
|
|
6
|
+
/** **(Optional)** Specify the Checkbox error state.
|
|
7
|
+
*
|
|
8
|
+
* This is an instance of `FormFieldError`. You can provide either an object with a `message` key, or a boolean value if you need to render the message independently.
|
|
9
|
+
*/
|
|
10
|
+
error?: FormFieldError;
|
|
11
|
+
/** **(Optional)** Specify the Checkbox hint.
|
|
12
|
+
*
|
|
13
|
+
* This text is rendered under the label to provide further guidance for users.
|
|
14
|
+
*/
|
|
15
|
+
hint?: string;
|
|
16
|
+
/** **(Optional)** Specify the Checkbox id. Will be auto-generated if not set. */
|
|
17
|
+
id?: string;
|
|
18
|
+
/** **(Optional)** Specify the Checkbox label.
|
|
19
|
+
*
|
|
20
|
+
* This property is optional in case you need to render your own label, but all form elements *must* provide a label. */
|
|
21
|
+
label: string;
|
|
22
|
+
/** **(Optional)** Specify whether the label should be visible to humans or screen readers. */
|
|
23
|
+
labelVisible?: boolean;
|
|
24
|
+
/** Specify the Checkbox name. */
|
|
25
|
+
name: string;
|
|
26
|
+
/** **(Optional)** Specify the Checkbox size. */
|
|
27
|
+
size?: StandardSizes;
|
|
28
|
+
}
|
|
29
|
+
export declare const Checkbox: ({ className, error, hint, id, label, labelVisible, name, size, ...props }: CheckboxProps) => JSX.Element;
|
|
30
|
+
export default Checkbox;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { clsx } from '../../node_modules/clsx/dist/clsx.js';
|
|
3
|
+
import { useId } from 'react';
|
|
4
|
+
import { FieldError } from '../FieldError/FieldError.js';
|
|
5
|
+
import { FieldHint } from '../FieldHint/FieldHint.js';
|
|
6
|
+
import { FieldLabel } from '../FieldLabel/FieldLabel.js';
|
|
7
|
+
|
|
8
|
+
const Checkbox = ({ className, error = false, hint, id, label, labelVisible = true, name, size = "md", ...props }) => {
|
|
9
|
+
const internalId = useId();
|
|
10
|
+
id = id !== null && id !== void 0 ? id : internalId;
|
|
11
|
+
const componentProps = {
|
|
12
|
+
className: clsx("coop-checkbox", className),
|
|
13
|
+
"data-error": error ? "" : undefined,
|
|
14
|
+
"data-size": size.length && size !== "md" ? size : undefined,
|
|
15
|
+
id,
|
|
16
|
+
name,
|
|
17
|
+
type: "checkbox",
|
|
18
|
+
...props,
|
|
19
|
+
};
|
|
20
|
+
return (jsxs("div", { className: "coop-form-item", children: [jsxs("div", { className: "coop-checkbox-wrapper", children: [jsx("input", { ...componentProps }), label && (jsx(FieldLabel, { htmlFor: id, isVisible: labelVisible, children: label })), hint && jsx(FieldHint, { children: hint })] }), typeof error === "object" && (error === null || error === void 0 ? void 0 : error.message) && jsx(FieldError, { children: error.message })] }));
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export { Checkbox, Checkbox as default };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { FieldsetHTMLAttributes, JSX } from "react";
|
|
2
|
+
import { FormFieldError, StandardSizes } from "../../../src/types";
|
|
3
|
+
export interface CheckboxGroupProps extends FieldsetHTMLAttributes<HTMLFieldSetElement> {
|
|
4
|
+
/** **(Optional)** Main content inside the component. It can be any valid JSX or string. */
|
|
5
|
+
children?: React.ReactNode;
|
|
6
|
+
/** **(Optional)** Specify additional CSS classes to be applied to the component. */
|
|
7
|
+
className?: string;
|
|
8
|
+
/** **(Optional)** Specify the CheckboxGroup error state.
|
|
9
|
+
*
|
|
10
|
+
* This is an instance of `FormFieldError`. You can provide either an object with a `message` key, or a boolean value if you need to render the message independently.
|
|
11
|
+
*/
|
|
12
|
+
error?: FormFieldError;
|
|
13
|
+
/** **(Optional)** Specify the CheckboxGroup hint.
|
|
14
|
+
*
|
|
15
|
+
* This text is rendered under the label to provide further guidance for users.
|
|
16
|
+
*/
|
|
17
|
+
hint?: string;
|
|
18
|
+
/** **(Optional)** Specify the label for the CheckboxGroup. This will be rendered as a fieldset legend. */
|
|
19
|
+
label?: string;
|
|
20
|
+
/** **(Optional)** Specify whether the label should be visible to humans or screen readers. */
|
|
21
|
+
labelVisible?: boolean;
|
|
22
|
+
/** **(Optional)** Specify the CheckboxGroup size. */
|
|
23
|
+
size?: StandardSizes;
|
|
24
|
+
}
|
|
25
|
+
export declare const CheckboxGroup: ({ children, className, error, hint, label, labelVisible, size, ...props }: CheckboxGroupProps) => JSX.Element;
|
|
26
|
+
export default CheckboxGroup;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { clsx } from '../../node_modules/clsx/dist/clsx.js';
|
|
3
|
+
import { FieldError } from '../FieldError/FieldError.js';
|
|
4
|
+
import { FieldHint } from '../FieldHint/FieldHint.js';
|
|
5
|
+
|
|
6
|
+
const CheckboxGroup = ({ children, className, error = false, hint, label, labelVisible = true, size = "md", ...props }) => {
|
|
7
|
+
const componentProps = {
|
|
8
|
+
className: clsx("coop-fieldset", "coop-checkbox-group", className),
|
|
9
|
+
"data-error": error ? "" : undefined,
|
|
10
|
+
"data-size": size.length && size !== "md" ? size : undefined,
|
|
11
|
+
...props,
|
|
12
|
+
};
|
|
13
|
+
const legendProps = {
|
|
14
|
+
className: clsx("coop-field-label", !labelVisible && "sr-only"),
|
|
15
|
+
};
|
|
16
|
+
return (jsxs("fieldset", { ...componentProps, children: [label && jsx("legend", { ...legendProps, children: label }), hint && jsx(FieldHint, { children: hint }), typeof error === "object" && (error === null || error === void 0 ? void 0 : error.message) && jsx(FieldError, { children: error.message }), children] }));
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export { CheckboxGroup, CheckboxGroup as default };
|
|
@@ -3,7 +3,7 @@ import { clsx } from '../../node_modules/clsx/dist/clsx.js';
|
|
|
3
3
|
|
|
4
4
|
const Field = ({ children, className, ...props }) => {
|
|
5
5
|
const componentProps = {
|
|
6
|
-
className: clsx("coop-
|
|
6
|
+
className: clsx("coop-form-item ", className),
|
|
7
7
|
...props,
|
|
8
8
|
};
|
|
9
9
|
return jsx("div", { ...componentProps, children: children });
|
|
@@ -6,7 +6,7 @@ const FieldHint = ({ children, className, ...props }) => {
|
|
|
6
6
|
className: clsx("coop-field-hint ", className),
|
|
7
7
|
...props,
|
|
8
8
|
};
|
|
9
|
-
return children ? jsx("
|
|
9
|
+
return children ? jsx("div", { ...componentProps, children: children }) : null;
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
export { FieldHint, FieldHint as default };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type InputHTMLAttributes, type JSX } from "react";
|
|
2
|
+
import { FormFieldError, StandardSizes } from "src/types";
|
|
3
|
+
export interface RadioButtonProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "size" | "type"> {
|
|
4
|
+
/** **(Optional)** Specify additional CSS classes to be applied to the component. */
|
|
5
|
+
className?: string;
|
|
6
|
+
/** **(Optional)** Specify the RadioButton error state.
|
|
7
|
+
*
|
|
8
|
+
* This is an instance of `FormFieldError`. You can provide either an object with a `message` key, or a boolean value if you need to render the message independently.
|
|
9
|
+
*/
|
|
10
|
+
error?: FormFieldError;
|
|
11
|
+
/** **(Optional)** Specify the RadioButton hint.
|
|
12
|
+
*
|
|
13
|
+
* This text is rendered under the label to provide further guidance for users.
|
|
14
|
+
*/
|
|
15
|
+
hint?: string;
|
|
16
|
+
/** **(Optional)** Specify the RadioButton id. Will be auto-generated if not set. */
|
|
17
|
+
id?: string;
|
|
18
|
+
/** **(Optional)** Specify the RadioButton label.
|
|
19
|
+
*
|
|
20
|
+
* This property is optional in case you need to render your own label, but all form elements *must* provide a label. */
|
|
21
|
+
label: string;
|
|
22
|
+
/** **(Optional)** Specify whether the label should be visible to humans or screen readers. */
|
|
23
|
+
labelVisible?: boolean;
|
|
24
|
+
/** Specify the RadioButton name. */
|
|
25
|
+
name: string;
|
|
26
|
+
/** **(Optional)** Specify the RadioButton size. */
|
|
27
|
+
size?: StandardSizes;
|
|
28
|
+
}
|
|
29
|
+
export declare const RadioButton: ({ className, error, hint, id, label, labelVisible, name, size, ...props }: RadioButtonProps) => JSX.Element;
|
|
30
|
+
export default RadioButton;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { clsx } from '../../node_modules/clsx/dist/clsx.js';
|
|
3
|
+
import { useId } from 'react';
|
|
4
|
+
import { FieldError } from '../FieldError/FieldError.js';
|
|
5
|
+
import { FieldHint } from '../FieldHint/FieldHint.js';
|
|
6
|
+
import { FieldLabel } from '../FieldLabel/FieldLabel.js';
|
|
7
|
+
|
|
8
|
+
const RadioButton = ({ className, error = false, hint, id, label, labelVisible = true, name, size = "md", ...props }) => {
|
|
9
|
+
const internalId = useId();
|
|
10
|
+
id = id !== null && id !== void 0 ? id : internalId;
|
|
11
|
+
const componentProps = {
|
|
12
|
+
className: clsx("coop-radio-button", className),
|
|
13
|
+
"data-error": error ? "" : undefined,
|
|
14
|
+
"data-size": size.length && size !== "md" ? size : undefined,
|
|
15
|
+
id,
|
|
16
|
+
name,
|
|
17
|
+
type: "radio",
|
|
18
|
+
...props,
|
|
19
|
+
};
|
|
20
|
+
return (jsxs("div", { className: "coop-form-item", children: [jsxs("div", { className: "coop-radio-button-wrapper", children: [jsx("input", { ...componentProps }), label && (jsx(FieldLabel, { htmlFor: id, isVisible: labelVisible, children: label })), hint && jsx(FieldHint, { children: hint })] }), typeof error === "object" && (error === null || error === void 0 ? void 0 : error.message) && jsx(FieldError, { children: error.message })] }));
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export { RadioButton, RadioButton as default };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { FieldsetHTMLAttributes, JSX } from "react";
|
|
2
|
+
import { FormFieldError, StandardSizes } from "../../types";
|
|
3
|
+
export interface RadioButtonGroupProps extends FieldsetHTMLAttributes<HTMLFieldSetElement> {
|
|
4
|
+
/** **(Optional)** Main content inside the component. It can be any valid JSX or string. */
|
|
5
|
+
children?: React.ReactNode;
|
|
6
|
+
/** **(Optional)** Specify additional CSS classes to be applied to the component. */
|
|
7
|
+
className?: string;
|
|
8
|
+
/** **(Optional)** Specify the RadioButtonGroup error state.
|
|
9
|
+
*
|
|
10
|
+
* This is an instance of `FormFieldError`. You can provide either an object with a `message` key, or a boolean value if you need to render the message independently.
|
|
11
|
+
*/
|
|
12
|
+
error?: FormFieldError;
|
|
13
|
+
/** **(Optional)** Specify the RadioButtonGroup hint.
|
|
14
|
+
*
|
|
15
|
+
* This text is rendered under the label to provide further guidance for users.
|
|
16
|
+
*/
|
|
17
|
+
hint?: string;
|
|
18
|
+
/** **(Optional)** Specify the label for the RadioButtonGroup. This will be rendered as a fieldset legend. */
|
|
19
|
+
label?: string;
|
|
20
|
+
/** **(Optional)** Specify whether the label should be visible to humans or screen readers. */
|
|
21
|
+
labelVisible?: boolean;
|
|
22
|
+
/** **(Optional)** Specify the RadioButtonGroup size. */
|
|
23
|
+
size?: StandardSizes;
|
|
24
|
+
}
|
|
25
|
+
export declare const RadioButtonGroup: ({ children, className, error, hint, label, labelVisible, size, ...props }: RadioButtonGroupProps) => JSX.Element;
|
|
26
|
+
export default RadioButtonGroup;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { clsx } from '../../node_modules/clsx/dist/clsx.js';
|
|
3
|
+
import { FieldError } from '../FieldError/FieldError.js';
|
|
4
|
+
import { FieldHint } from '../FieldHint/FieldHint.js';
|
|
5
|
+
|
|
6
|
+
const RadioButtonGroup = ({ children, className, error = false, hint, label, labelVisible = true, size = "md", ...props }) => {
|
|
7
|
+
const componentProps = {
|
|
8
|
+
className: clsx("coop-fieldset", "coop-radio-button-group", className),
|
|
9
|
+
"data-error": error ? "" : undefined,
|
|
10
|
+
"data-size": size.length && size !== "md" ? size : undefined,
|
|
11
|
+
...props,
|
|
12
|
+
};
|
|
13
|
+
const legendProps = {
|
|
14
|
+
className: clsx("coop-field-label", !labelVisible && "sr-only"),
|
|
15
|
+
};
|
|
16
|
+
return (jsxs("fieldset", { ...componentProps, children: [label && jsx("legend", { ...legendProps, children: label }), hint && jsx(FieldHint, { children: hint }), typeof error === "object" && (error === null || error === void 0 ? void 0 : error.message) && jsx(FieldError, { children: error.message }), children] }));
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export { RadioButtonGroup, RadioButtonGroup as default };
|
|
@@ -11,17 +11,17 @@ export interface SearchBoxProps extends Omit<InputHTMLAttributes<HTMLInputElemen
|
|
|
11
11
|
};
|
|
12
12
|
/** **(Optional)** Specify additional CSS classes to be applied to the component. */
|
|
13
13
|
className?: string;
|
|
14
|
-
/** **(Optional)** Specify the
|
|
14
|
+
/** **(Optional)** Specify the TextInput id. Will be auto-generated if not set. */
|
|
15
15
|
id?: string;
|
|
16
16
|
/** Specify the label displayed above the search field. Hidden by default, but visible to screen readers. */
|
|
17
17
|
label: string;
|
|
18
18
|
/** **(Optional)** Specify whether the label should be visible to humans or screenreaders. */
|
|
19
19
|
labelVisible?: boolean;
|
|
20
|
-
/** **(Optional)** Specify the
|
|
20
|
+
/** **(Optional)** Specify the TextInput name, also used as the URL search parameter. Defaults to `query`. */
|
|
21
21
|
name?: string;
|
|
22
22
|
/** **(Optional)** Callback to run when the form is submitted. If this is an async function, it will be awaited and the SearchBox will be in a pending state until the promise is resolved. */
|
|
23
23
|
onSubmit?: React.FormEventHandler<HTMLElement> | undefined;
|
|
24
|
-
/** **(Optional)** Specify the
|
|
24
|
+
/** **(Optional)** Specify the TextInput placeholder text Do not use in place of a form label. */
|
|
25
25
|
placeholder?: string;
|
|
26
26
|
/** **(Optional)** Specify the SearchBox size. */
|
|
27
27
|
size?: StandardSizes;
|
|
@@ -6,7 +6,7 @@ import React, { useState, useId, useCallback } from 'react';
|
|
|
6
6
|
import { Button } from '../Button/Button.js';
|
|
7
7
|
import { FieldLabel } from '../FieldLabel/FieldLabel.js';
|
|
8
8
|
import { SearchIcon } from '../Icon/SearchIcon.js';
|
|
9
|
-
import {
|
|
9
|
+
import { TextInput } from '../TextInput/TextInput.js';
|
|
10
10
|
|
|
11
11
|
const defaultButtonProps = {
|
|
12
12
|
label: React.createElement(SearchIcon, { alt: "Search", stroke: "currentColor", strokeWidth: 2 }),
|
|
@@ -54,7 +54,7 @@ const SearchBox = ({ action, "aria-placeholder": ariaPlaceholder, autoCapitalize
|
|
|
54
54
|
type: "search",
|
|
55
55
|
...props,
|
|
56
56
|
};
|
|
57
|
-
return (jsxs("form", { ...formProps, children: [label && (jsx(FieldLabel, { htmlFor: id, isVisible: labelVisible, children: label })), jsxs("div", { className: "coop-search-box--inner", children: [jsx(
|
|
57
|
+
return (jsxs("form", { ...formProps, children: [label && (jsx(FieldLabel, { htmlFor: id, isVisible: labelVisible, children: label })), jsxs("div", { className: "coop-search-box--inner", children: [jsx(TextInput, { ...inputProps }), jsx(Button, { ...buttonProps, children: button.label })] })] }));
|
|
58
58
|
};
|
|
59
59
|
|
|
60
60
|
export { SearchBox, SearchBox as default };
|
|
@@ -1,34 +1,38 @@
|
|
|
1
1
|
import type { InputHTMLAttributes, JSX } from "react";
|
|
2
2
|
import { FormFieldError, StandardSizes } from "../../../src/types";
|
|
3
|
-
export interface
|
|
3
|
+
export interface TextInputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "size" | "type"> {
|
|
4
4
|
/** **(Optional)** Specify additional CSS classes to be applied to the component. */
|
|
5
5
|
className?: string;
|
|
6
|
-
/** **(Optional)** Specify the
|
|
6
|
+
/** **(Optional)** Specify the TextInput error state.
|
|
7
7
|
*
|
|
8
8
|
* This is an instance of `FormFieldError`. You can provide either an object with a `message` key, or a boolean value if you need to render the message independently.
|
|
9
9
|
*/
|
|
10
10
|
error?: FormFieldError;
|
|
11
|
-
/** **(Optional)** Specify the
|
|
11
|
+
/** **(Optional)** Specify the TextInput hint.
|
|
12
12
|
*
|
|
13
13
|
* This text is rendered under the label to provide further guidance for users.
|
|
14
14
|
*/
|
|
15
15
|
hint?: string;
|
|
16
|
-
/** **(Optional)** Specify the
|
|
16
|
+
/** **(Optional)** Specify the TextInput id. Will be auto-generated if not set. */
|
|
17
17
|
id?: string;
|
|
18
|
-
/** **(Optional)** Specify the
|
|
18
|
+
/** **(Optional)** Specify the TextInput label.
|
|
19
19
|
*
|
|
20
20
|
* This property is optional in case you need to render your own label, but all form elements *must* provide a label. */
|
|
21
21
|
label?: string;
|
|
22
22
|
/** **(Optional)** Specify whether the label should be visible to humans or screen readers. */
|
|
23
23
|
labelVisible?: boolean;
|
|
24
|
-
/** Specify the
|
|
24
|
+
/** Specify the TextInput name. */
|
|
25
25
|
name: string;
|
|
26
|
-
/** **(Optional)** Specify the
|
|
26
|
+
/** **(Optional)** Specify the TextInput placeholder text. Do not use in place of a form label. */
|
|
27
27
|
placeholder?: string;
|
|
28
|
-
/** **(Optional)** Specify the
|
|
28
|
+
/** **(Optional)** Specify the prefix. */
|
|
29
|
+
prefix?: string;
|
|
30
|
+
/** **(Optional)** Specify the TextInput size. */
|
|
29
31
|
size?: StandardSizes;
|
|
30
|
-
/** **(Optional)** Specify the
|
|
32
|
+
/** **(Optional)** Specify the suffix. */
|
|
33
|
+
suffix?: string;
|
|
34
|
+
/** **(Optional)** Specify the TextInput type. */
|
|
31
35
|
type?: "text" | "email" | "number" | "password" | "search" | "tel" | "url";
|
|
32
36
|
}
|
|
33
|
-
export declare const
|
|
34
|
-
export default
|
|
37
|
+
export declare const TextInput: ({ "aria-placeholder": ariaPlaceholder, className, error, hint, id, label, labelVisible, name, placeholder, prefix, size, suffix, type, ...props }: TextInputProps) => JSX.Element;
|
|
38
|
+
export default TextInput;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { clsx } from '../../node_modules/clsx/dist/clsx.js';
|
|
3
|
+
import { useId } from 'react';
|
|
4
|
+
import { FieldError } from '../FieldError/FieldError.js';
|
|
5
|
+
import { FieldHint } from '../FieldHint/FieldHint.js';
|
|
6
|
+
import { FieldLabel } from '../FieldLabel/FieldLabel.js';
|
|
7
|
+
|
|
8
|
+
const TextInput = ({ "aria-placeholder": ariaPlaceholder, className, error = false, hint, id, label, labelVisible = true, name, placeholder, prefix, size = "md", suffix, type = "text", ...props }) => {
|
|
9
|
+
var _a;
|
|
10
|
+
const internalId = useId();
|
|
11
|
+
id = id !== null && id !== void 0 ? id : internalId;
|
|
12
|
+
const componentProps = {
|
|
13
|
+
"aria-placeholder": (_a = placeholder !== null && placeholder !== void 0 ? placeholder : ariaPlaceholder) !== null && _a !== void 0 ? _a : undefined,
|
|
14
|
+
className: clsx("coop-text-input", className),
|
|
15
|
+
"data-error": error ? "" : undefined,
|
|
16
|
+
"data-size": size.length && size !== "md" ? size : undefined,
|
|
17
|
+
id,
|
|
18
|
+
name,
|
|
19
|
+
placeholder,
|
|
20
|
+
type,
|
|
21
|
+
...props,
|
|
22
|
+
};
|
|
23
|
+
return (jsxs("div", { className: "coop-form-item", children: [label && (jsx(FieldLabel, { htmlFor: id, isVisible: labelVisible, children: label })), hint && jsx(FieldHint, { children: hint }), typeof error === "object" && (error === null || error === void 0 ? void 0 : error.message) && jsx(FieldError, { children: error.message }), jsxs("div", { className: "coop-text-input-wrapper", children: [prefix && jsx("span", { className: "coop-text-input--prefix", children: prefix }), jsx("input", { ...componentProps }), suffix && jsx("span", { className: "coop-text-input--suffix", children: suffix })] })] }));
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export { TextInput, TextInput as default };
|
|
@@ -5,6 +5,8 @@ export interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElemen
|
|
|
5
5
|
className?: string;
|
|
6
6
|
/** Specify the number of columns (characters per row) in the Textarea. Defaults to `30`. */
|
|
7
7
|
cols?: number;
|
|
8
|
+
/** **(Optional)** Specify whether to show the character counter underneath the Textarea. */
|
|
9
|
+
counter?: boolean;
|
|
8
10
|
/** **(Optional)** Specify whether the Textarea should allow more characters than its `maxLength` value.
|
|
9
11
|
*
|
|
10
12
|
* Defaults to `false`, meaning users can enter more characters than the maximum but will be warned if they go over the limit. When set to `true`, users will be blocked from typing once they hit the character limit. This can be an accessiblity anti-pattern, so only use this option when absolutely necessary.
|
|
@@ -38,10 +40,8 @@ export interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElemen
|
|
|
38
40
|
placeholder?: string;
|
|
39
41
|
/** Specify the number of rows (lines of text) in the Textarea. Defaults to `4`. */
|
|
40
42
|
rows?: number;
|
|
41
|
-
/** **(Optional)** Specify whether to show the remaining character count underneath the Textarea. */
|
|
42
|
-
showRemaining?: boolean;
|
|
43
43
|
/** **(Optional)** Specify the Textarea size. */
|
|
44
44
|
size?: StandardSizes;
|
|
45
45
|
}
|
|
46
|
-
export declare const Textarea: ({ "aria-placeholder": ariaPlaceholder, className, cols, cutoff, error, hint, id, label, labelVisible, maxLength, name, onChange: userOnChange, placeholder, rows,
|
|
46
|
+
export declare const Textarea: ({ "aria-placeholder": ariaPlaceholder, className, cols, counter, cutoff, error, hint, id, label, labelVisible, maxLength, name, onChange: userOnChange, placeholder, rows, size, ...props }: TextareaProps) => JSX.Element;
|
|
47
47
|
export default Textarea;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsxs,
|
|
1
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
2
2
|
import { clsx } from '../../node_modules/clsx/dist/clsx.js';
|
|
3
3
|
import { useId, useState } from 'react';
|
|
4
4
|
import { useDebounce } from '../../hooks/useDebounce.js';
|
|
@@ -8,9 +8,9 @@ import { FieldLabel } from '../FieldLabel/FieldLabel.js';
|
|
|
8
8
|
|
|
9
9
|
const DEBOUNCE_DELAY = 750;
|
|
10
10
|
const charCountMessage = (remaining) => {
|
|
11
|
-
return `You have ${Math.abs(remaining)} ${Math.abs(remaining) === 1 ? "character" : "characters"} ${remaining < 0 ? "too many" : "remaining"}`;
|
|
11
|
+
return `You have ${Math.abs(remaining).toLocaleString()} ${Math.abs(remaining) === 1 ? "character" : "characters"} ${remaining < 0 ? "too many" : "remaining"}`;
|
|
12
12
|
};
|
|
13
|
-
const Textarea = ({ "aria-placeholder": ariaPlaceholder, className, cols = 30, cutoff = false, error = false, hint, id, label, labelVisible = true, maxLength, name, onChange: userOnChange = undefined, placeholder, rows = 4,
|
|
13
|
+
const Textarea = ({ "aria-placeholder": ariaPlaceholder, className, cols = 30, counter = false, cutoff = false, error = false, hint, id, label, labelVisible = true, maxLength, name, onChange: userOnChange = undefined, placeholder, rows = 4, size = "md", ...props }) => {
|
|
14
14
|
var _a;
|
|
15
15
|
const internalId = useId();
|
|
16
16
|
id = id !== null && id !== void 0 ? id : internalId;
|
|
@@ -32,10 +32,10 @@ const Textarea = ({ "aria-placeholder": ariaPlaceholder, className, cols = 30, c
|
|
|
32
32
|
const handleChange = (e) => {
|
|
33
33
|
maxLength && e.target && setRemaining(maxLength - e.target.value.length);
|
|
34
34
|
};
|
|
35
|
-
return (jsxs(
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
35
|
+
return (jsxs("div", { className: "coop-form-item", children: [label && (jsx(FieldLabel, { htmlFor: id, isVisible: labelVisible, children: label })), hint && jsx(FieldHint, { children: hint }), typeof error === "object" && (error === null || error === void 0 ? void 0 : error.message) && jsx(FieldError, { children: error.message }), jsx("textarea", { ...componentProps, onChange: (e) => {
|
|
36
|
+
userOnChange === null || userOnChange === void 0 ? void 0 : userOnChange(e);
|
|
37
|
+
handleChange(e);
|
|
38
|
+
} }), counter && maxLength && remaining != null && debouncedRemaining != null && (jsxs(Fragment, { children: [jsx("small", { "aria-hidden": "true", className: "coop-textarea-counter", ...(remaining < 0 && { "data-error": "" }), children: charCountMessage(remaining) }), jsx("span", { "aria-live": "polite", className: "sr-only", children: charCountMessage(debouncedRemaining) })] }))] }));
|
|
39
39
|
};
|
|
40
40
|
|
|
41
41
|
export { Textarea, Textarea as default };
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export * from "./components/AlertBanner";
|
|
|
2
2
|
export * from "./components/Author";
|
|
3
3
|
export * from "./components/Button";
|
|
4
4
|
export * from "./components/Card";
|
|
5
|
+
export * from "./components/Checkbox";
|
|
5
6
|
export * from "./components/Expandable";
|
|
6
7
|
export * from "./components/Field";
|
|
7
8
|
export * from "./components/FieldError";
|
|
@@ -9,8 +10,8 @@ export * from "./components/FieldHint";
|
|
|
9
10
|
export * from "./components/FieldLabel";
|
|
10
11
|
export * from "./components/Flourish";
|
|
11
12
|
export * from "./components/Image";
|
|
12
|
-
export * from "./components/Input";
|
|
13
13
|
export * from "./components/Pill";
|
|
14
|
+
export * from "./components/RadioButton";
|
|
14
15
|
export * from "./components/RootSVG";
|
|
15
16
|
export * from "./components/SearchBox";
|
|
16
17
|
export * from "./components/Signpost";
|
|
@@ -18,3 +19,4 @@ export * from "./components/SkipNav";
|
|
|
18
19
|
export * from "./components/Squircle";
|
|
19
20
|
export * from "./components/Tag";
|
|
20
21
|
export * from "./components/Textarea";
|
|
22
|
+
export * from "./components/TextInput";
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,8 @@ export { AlertBanner } from './components/AlertBanner/AlertBanner.js';
|
|
|
2
2
|
export { Author } from './components/Author/Author.js';
|
|
3
3
|
export { Button } from './components/Button/Button.js';
|
|
4
4
|
export { Card } from './components/Card/Card.js';
|
|
5
|
+
export { Checkbox } from './components/Checkbox/Checkbox.js';
|
|
6
|
+
export { CheckboxGroup } from './components/Checkbox/CheckboxGroup.js';
|
|
5
7
|
export { Expandable } from './components/Expandable/Expandable.js';
|
|
6
8
|
export { Field } from './components/Field/Field.js';
|
|
7
9
|
export { FieldError } from './components/FieldError/FieldError.js';
|
|
@@ -9,8 +11,9 @@ export { FieldHint } from './components/FieldHint/FieldHint.js';
|
|
|
9
11
|
export { FieldLabel } from './components/FieldLabel/FieldLabel.js';
|
|
10
12
|
export { Flourish } from './components/Flourish/Flourish.js';
|
|
11
13
|
export { Image } from './components/Image/Image.js';
|
|
12
|
-
export { Input } from './components/Input/Input.js';
|
|
13
14
|
export { Pill } from './components/Pill/Pill.js';
|
|
15
|
+
export { RadioButton } from './components/RadioButton/RadioButton.js';
|
|
16
|
+
export { RadioButtonGroup } from './components/RadioButton/RadioButtonGroup.js';
|
|
14
17
|
export { RootSVG } from './components/RootSVG/RootSVG.js';
|
|
15
18
|
export { SearchBox } from './components/SearchBox/SearchBox.js';
|
|
16
19
|
export { Signpost } from './components/Signpost/Signpost.js';
|
|
@@ -18,3 +21,4 @@ export { SkipNav } from './components/SkipNav/SkipNav.js';
|
|
|
18
21
|
export { Squircle } from './components/Squircle/Squircle.js';
|
|
19
22
|
export { Tag } from './components/Tag/Tag.js';
|
|
20
23
|
export { Textarea } from './components/Textarea/Textarea.js';
|
|
24
|
+
export { TextInput } from './components/TextInput/TextInput.js';
|
package/dist/types/index.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coopdigital/react",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.36.0",
|
|
5
5
|
"private": false,
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"access": "public"
|
|
@@ -57,19 +57,19 @@
|
|
|
57
57
|
"devDependencies": {
|
|
58
58
|
"@axe-core/playwright": "^4.10.2",
|
|
59
59
|
"@playwright/test": "^1.55.0",
|
|
60
|
-
"@storybook/addon-a11y": "^9.1.
|
|
61
|
-
"@storybook/addon-docs": "^9.1.
|
|
62
|
-
"@storybook/addon-onboarding": "^9.1.
|
|
63
|
-
"@storybook/react-vite": "^9.1.
|
|
60
|
+
"@storybook/addon-a11y": "^9.1.5",
|
|
61
|
+
"@storybook/addon-docs": "^9.1.5",
|
|
62
|
+
"@storybook/addon-onboarding": "^9.1.5",
|
|
63
|
+
"@storybook/react-vite": "^9.1.5",
|
|
64
64
|
"@testing-library/jest-dom": "^6.8.0",
|
|
65
65
|
"@testing-library/react": "^16.3.0",
|
|
66
|
-
"@types/react": "^19.1.
|
|
66
|
+
"@types/react": "^19.1.13",
|
|
67
67
|
"@types/react-dom": "^19.1.9",
|
|
68
68
|
"clsx": "^2.1.1",
|
|
69
69
|
"react": "^19.1.1",
|
|
70
70
|
"react-dom": "^19.1.1",
|
|
71
|
-
"serve": "^14.2.
|
|
72
|
-
"storybook": "^9.1.
|
|
71
|
+
"serve": "^14.2.5",
|
|
72
|
+
"storybook": "^9.1.5"
|
|
73
73
|
},
|
|
74
74
|
"peerDependencies": {
|
|
75
75
|
"clsx": "^2.1.1",
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
"storybook": "$storybook"
|
|
81
81
|
},
|
|
82
82
|
"dependencies": {
|
|
83
|
-
"@coopdigital/styles": "^0.
|
|
83
|
+
"@coopdigital/styles": "^0.31.1"
|
|
84
84
|
},
|
|
85
|
-
"gitHead": "
|
|
85
|
+
"gitHead": "a88bc2694b91f0c180f02d39786a1323e6632254"
|
|
86
86
|
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { InputHTMLAttributes, JSX } from "react"
|
|
2
|
+
|
|
3
|
+
import clsx from "clsx"
|
|
4
|
+
import { useId } from "react"
|
|
5
|
+
|
|
6
|
+
import { FormFieldError, StandardSizes } from "../../../src/types"
|
|
7
|
+
import { FieldError } from "../FieldError"
|
|
8
|
+
import { FieldHint } from "../FieldHint"
|
|
9
|
+
import { FieldLabel } from "../FieldLabel"
|
|
10
|
+
|
|
11
|
+
export interface CheckboxProps
|
|
12
|
+
extends Omit<InputHTMLAttributes<HTMLInputElement>, "size" | "type"> {
|
|
13
|
+
/** **(Optional)** Specify additional CSS classes to be applied to the component. */
|
|
14
|
+
className?: string
|
|
15
|
+
/** **(Optional)** Specify the Checkbox error state.
|
|
16
|
+
*
|
|
17
|
+
* This is an instance of `FormFieldError`. You can provide either an object with a `message` key, or a boolean value if you need to render the message independently.
|
|
18
|
+
*/
|
|
19
|
+
error?: FormFieldError
|
|
20
|
+
/** **(Optional)** Specify the Checkbox hint.
|
|
21
|
+
*
|
|
22
|
+
* This text is rendered under the label to provide further guidance for users.
|
|
23
|
+
*/
|
|
24
|
+
hint?: string
|
|
25
|
+
/** **(Optional)** Specify the Checkbox id. Will be auto-generated if not set. */
|
|
26
|
+
id?: string
|
|
27
|
+
/** **(Optional)** Specify the Checkbox label.
|
|
28
|
+
*
|
|
29
|
+
* This property is optional in case you need to render your own label, but all form elements *must* provide a label. */
|
|
30
|
+
label: string
|
|
31
|
+
/** **(Optional)** Specify whether the label should be visible to humans or screen readers. */
|
|
32
|
+
labelVisible?: boolean
|
|
33
|
+
/** Specify the Checkbox name. */
|
|
34
|
+
name: string
|
|
35
|
+
/** **(Optional)** Specify the Checkbox size. */
|
|
36
|
+
size?: StandardSizes
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const Checkbox = ({
|
|
40
|
+
className,
|
|
41
|
+
error = false,
|
|
42
|
+
hint,
|
|
43
|
+
id,
|
|
44
|
+
label,
|
|
45
|
+
labelVisible = true,
|
|
46
|
+
name,
|
|
47
|
+
size = "md",
|
|
48
|
+
...props
|
|
49
|
+
}: CheckboxProps): JSX.Element => {
|
|
50
|
+
const internalId = useId()
|
|
51
|
+
|
|
52
|
+
id = id ?? internalId
|
|
53
|
+
|
|
54
|
+
const componentProps = {
|
|
55
|
+
className: clsx("coop-checkbox", className),
|
|
56
|
+
"data-error": error ? "" : undefined,
|
|
57
|
+
"data-size": size.length && size !== "md" ? size : undefined,
|
|
58
|
+
id,
|
|
59
|
+
name,
|
|
60
|
+
type: "checkbox",
|
|
61
|
+
...props,
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<div className="coop-form-item">
|
|
66
|
+
<div className="coop-checkbox-wrapper">
|
|
67
|
+
<input {...componentProps} />
|
|
68
|
+
|
|
69
|
+
{label && (
|
|
70
|
+
<FieldLabel htmlFor={id} isVisible={labelVisible}>
|
|
71
|
+
{label}
|
|
72
|
+
</FieldLabel>
|
|
73
|
+
)}
|
|
74
|
+
{hint && <FieldHint>{hint}</FieldHint>}
|
|
75
|
+
</div>
|
|
76
|
+
{typeof error === "object" && error?.message && <FieldError>{error.message}</FieldError>}
|
|
77
|
+
</div>
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export default Checkbox
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { FieldsetHTMLAttributes, JSX } from "react"
|
|
2
|
+
|
|
3
|
+
import clsx from "clsx"
|
|
4
|
+
|
|
5
|
+
import { FormFieldError, StandardSizes } from "../../../src/types"
|
|
6
|
+
import { FieldError } from "../FieldError"
|
|
7
|
+
import { FieldHint } from "../FieldHint"
|
|
8
|
+
|
|
9
|
+
export interface CheckboxGroupProps extends FieldsetHTMLAttributes<HTMLFieldSetElement> {
|
|
10
|
+
/** **(Optional)** Main content inside the component. It can be any valid JSX or string. */
|
|
11
|
+
children?: React.ReactNode
|
|
12
|
+
/** **(Optional)** Specify additional CSS classes to be applied to the component. */
|
|
13
|
+
className?: string
|
|
14
|
+
/** **(Optional)** Specify the CheckboxGroup error state.
|
|
15
|
+
*
|
|
16
|
+
* This is an instance of `FormFieldError`. You can provide either an object with a `message` key, or a boolean value if you need to render the message independently.
|
|
17
|
+
*/
|
|
18
|
+
error?: FormFieldError
|
|
19
|
+
/** **(Optional)** Specify the CheckboxGroup hint.
|
|
20
|
+
*
|
|
21
|
+
* This text is rendered under the label to provide further guidance for users.
|
|
22
|
+
*/
|
|
23
|
+
hint?: string
|
|
24
|
+
/** **(Optional)** Specify the label for the CheckboxGroup. This will be rendered as a fieldset legend. */
|
|
25
|
+
label?: string
|
|
26
|
+
/** **(Optional)** Specify whether the label should be visible to humans or screen readers. */
|
|
27
|
+
labelVisible?: boolean
|
|
28
|
+
/** **(Optional)** Specify the CheckboxGroup size. */
|
|
29
|
+
size?: StandardSizes
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const CheckboxGroup = ({
|
|
33
|
+
children,
|
|
34
|
+
className,
|
|
35
|
+
error = false,
|
|
36
|
+
hint,
|
|
37
|
+
label,
|
|
38
|
+
labelVisible = true,
|
|
39
|
+
size = "md",
|
|
40
|
+
...props
|
|
41
|
+
}: CheckboxGroupProps): JSX.Element => {
|
|
42
|
+
const componentProps = {
|
|
43
|
+
className: clsx("coop-fieldset", "coop-checkbox-group", className),
|
|
44
|
+
"data-error": error ? "" : undefined,
|
|
45
|
+
"data-size": size.length && size !== "md" ? size : undefined,
|
|
46
|
+
...props,
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const legendProps = {
|
|
50
|
+
className: clsx("coop-field-label", !labelVisible && "sr-only"),
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<fieldset {...componentProps}>
|
|
55
|
+
{label && <legend {...legendProps}>{label}</legend>}
|
|
56
|
+
{hint && <FieldHint>{hint}</FieldHint>}
|
|
57
|
+
{typeof error === "object" && error?.message && <FieldError>{error.message}</FieldError>}
|
|
58
|
+
{children}
|
|
59
|
+
</fieldset>
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export default CheckboxGroup
|
|
@@ -11,7 +11,7 @@ export interface FieldProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
11
11
|
|
|
12
12
|
export const Field = ({ children, className, ...props }: FieldProps): JSX.Element => {
|
|
13
13
|
const componentProps = {
|
|
14
|
-
className: clsx("coop-
|
|
14
|
+
className: clsx("coop-form-item ", className),
|
|
15
15
|
...props,
|
|
16
16
|
}
|
|
17
17
|
return <div {...componentProps}>{children}</div>
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import clsx from "clsx"
|
|
2
|
+
import { type InputHTMLAttributes, type JSX, useId } from "react"
|
|
3
|
+
import { FormFieldError, StandardSizes } from "src/types"
|
|
4
|
+
|
|
5
|
+
import { FieldError } from "../FieldError"
|
|
6
|
+
import { FieldHint } from "../FieldHint"
|
|
7
|
+
import { FieldLabel } from "../FieldLabel"
|
|
8
|
+
|
|
9
|
+
export interface RadioButtonProps
|
|
10
|
+
extends Omit<InputHTMLAttributes<HTMLInputElement>, "size" | "type"> {
|
|
11
|
+
/** **(Optional)** Specify additional CSS classes to be applied to the component. */
|
|
12
|
+
className?: string
|
|
13
|
+
/** **(Optional)** Specify the RadioButton error state.
|
|
14
|
+
*
|
|
15
|
+
* This is an instance of `FormFieldError`. You can provide either an object with a `message` key, or a boolean value if you need to render the message independently.
|
|
16
|
+
*/
|
|
17
|
+
error?: FormFieldError
|
|
18
|
+
/** **(Optional)** Specify the RadioButton hint.
|
|
19
|
+
*
|
|
20
|
+
* This text is rendered under the label to provide further guidance for users.
|
|
21
|
+
*/
|
|
22
|
+
hint?: string
|
|
23
|
+
/** **(Optional)** Specify the RadioButton id. Will be auto-generated if not set. */
|
|
24
|
+
id?: string
|
|
25
|
+
/** **(Optional)** Specify the RadioButton label.
|
|
26
|
+
*
|
|
27
|
+
* This property is optional in case you need to render your own label, but all form elements *must* provide a label. */
|
|
28
|
+
label: string
|
|
29
|
+
/** **(Optional)** Specify whether the label should be visible to humans or screen readers. */
|
|
30
|
+
labelVisible?: boolean
|
|
31
|
+
/** Specify the RadioButton name. */
|
|
32
|
+
name: string
|
|
33
|
+
/** **(Optional)** Specify the RadioButton size. */
|
|
34
|
+
size?: StandardSizes
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const RadioButton = ({
|
|
38
|
+
className,
|
|
39
|
+
error = false,
|
|
40
|
+
hint,
|
|
41
|
+
id,
|
|
42
|
+
label,
|
|
43
|
+
labelVisible = true,
|
|
44
|
+
name,
|
|
45
|
+
size = "md",
|
|
46
|
+
...props
|
|
47
|
+
}: RadioButtonProps): JSX.Element => {
|
|
48
|
+
const internalId = useId()
|
|
49
|
+
|
|
50
|
+
id = id ?? internalId
|
|
51
|
+
|
|
52
|
+
const componentProps = {
|
|
53
|
+
className: clsx("coop-radio-button", className),
|
|
54
|
+
"data-error": error ? "" : undefined,
|
|
55
|
+
"data-size": size.length && size !== "md" ? size : undefined,
|
|
56
|
+
id,
|
|
57
|
+
name,
|
|
58
|
+
type: "radio",
|
|
59
|
+
...props,
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<div className="coop-form-item">
|
|
64
|
+
<div className="coop-radio-button-wrapper">
|
|
65
|
+
<input {...componentProps} />
|
|
66
|
+
|
|
67
|
+
{label && (
|
|
68
|
+
<FieldLabel htmlFor={id} isVisible={labelVisible}>
|
|
69
|
+
{label}
|
|
70
|
+
</FieldLabel>
|
|
71
|
+
)}
|
|
72
|
+
{hint && <FieldHint>{hint}</FieldHint>}
|
|
73
|
+
</div>
|
|
74
|
+
{typeof error === "object" && error?.message && <FieldError>{error.message}</FieldError>}
|
|
75
|
+
</div>
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export default RadioButton
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { FieldsetHTMLAttributes, JSX } from "react"
|
|
2
|
+
|
|
3
|
+
import clsx from "clsx"
|
|
4
|
+
|
|
5
|
+
import { FormFieldError, StandardSizes } from "../../types"
|
|
6
|
+
import { FieldError } from "../FieldError"
|
|
7
|
+
import { FieldHint } from "../FieldHint"
|
|
8
|
+
|
|
9
|
+
export interface RadioButtonGroupProps extends FieldsetHTMLAttributes<HTMLFieldSetElement> {
|
|
10
|
+
/** **(Optional)** Main content inside the component. It can be any valid JSX or string. */
|
|
11
|
+
children?: React.ReactNode
|
|
12
|
+
/** **(Optional)** Specify additional CSS classes to be applied to the component. */
|
|
13
|
+
className?: string
|
|
14
|
+
/** **(Optional)** Specify the RadioButtonGroup error state.
|
|
15
|
+
*
|
|
16
|
+
* This is an instance of `FormFieldError`. You can provide either an object with a `message` key, or a boolean value if you need to render the message independently.
|
|
17
|
+
*/
|
|
18
|
+
error?: FormFieldError
|
|
19
|
+
/** **(Optional)** Specify the RadioButtonGroup hint.
|
|
20
|
+
*
|
|
21
|
+
* This text is rendered under the label to provide further guidance for users.
|
|
22
|
+
*/
|
|
23
|
+
hint?: string
|
|
24
|
+
/** **(Optional)** Specify the label for the RadioButtonGroup. This will be rendered as a fieldset legend. */
|
|
25
|
+
label?: string
|
|
26
|
+
/** **(Optional)** Specify whether the label should be visible to humans or screen readers. */
|
|
27
|
+
labelVisible?: boolean
|
|
28
|
+
/** **(Optional)** Specify the RadioButtonGroup size. */
|
|
29
|
+
size?: StandardSizes
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const RadioButtonGroup = ({
|
|
33
|
+
children,
|
|
34
|
+
className,
|
|
35
|
+
error = false,
|
|
36
|
+
hint,
|
|
37
|
+
label,
|
|
38
|
+
labelVisible = true,
|
|
39
|
+
size = "md",
|
|
40
|
+
...props
|
|
41
|
+
}: RadioButtonGroupProps): JSX.Element => {
|
|
42
|
+
const componentProps = {
|
|
43
|
+
className: clsx("coop-fieldset", "coop-radio-button-group", className),
|
|
44
|
+
"data-error": error ? "" : undefined,
|
|
45
|
+
"data-size": size.length && size !== "md" ? size : undefined,
|
|
46
|
+
...props,
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const legendProps = {
|
|
50
|
+
className: clsx("coop-field-label", !labelVisible && "sr-only"),
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<fieldset {...componentProps}>
|
|
55
|
+
{label && <legend {...legendProps}>{label}</legend>}
|
|
56
|
+
{hint && <FieldHint>{hint}</FieldHint>}
|
|
57
|
+
{typeof error === "object" && error?.message && <FieldError>{error.message}</FieldError>}
|
|
58
|
+
{children}
|
|
59
|
+
</fieldset>
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export default RadioButtonGroup
|
|
@@ -9,7 +9,7 @@ import { StandardSizes } from "../../../src/types"
|
|
|
9
9
|
import { Button, type ButtonProps } from "../Button"
|
|
10
10
|
import { FieldLabel } from "../FieldLabel"
|
|
11
11
|
import { SearchIcon } from "../Icon"
|
|
12
|
-
import
|
|
12
|
+
import TextInput, { TextInputProps } from "../TextInput"
|
|
13
13
|
|
|
14
14
|
export interface SearchBoxProps
|
|
15
15
|
extends Omit<InputHTMLAttributes<HTMLInputElement>, "size" | "type"> {
|
|
@@ -19,17 +19,17 @@ export interface SearchBoxProps
|
|
|
19
19
|
button?: Pick<ButtonProps, "className" | "loadingText"> & { label?: React.ReactNode }
|
|
20
20
|
/** **(Optional)** Specify additional CSS classes to be applied to the component. */
|
|
21
21
|
className?: string
|
|
22
|
-
/** **(Optional)** Specify the
|
|
22
|
+
/** **(Optional)** Specify the TextInput id. Will be auto-generated if not set. */
|
|
23
23
|
id?: string
|
|
24
24
|
/** Specify the label displayed above the search field. Hidden by default, but visible to screen readers. */
|
|
25
25
|
label: string
|
|
26
26
|
/** **(Optional)** Specify whether the label should be visible to humans or screenreaders. */
|
|
27
27
|
labelVisible?: boolean
|
|
28
|
-
/** **(Optional)** Specify the
|
|
28
|
+
/** **(Optional)** Specify the TextInput name, also used as the URL search parameter. Defaults to `query`. */
|
|
29
29
|
name?: string
|
|
30
30
|
/** **(Optional)** Callback to run when the form is submitted. If this is an async function, it will be awaited and the SearchBox will be in a pending state until the promise is resolved. */
|
|
31
31
|
onSubmit?: React.FormEventHandler<HTMLElement> | undefined
|
|
32
|
-
/** **(Optional)** Specify the
|
|
32
|
+
/** **(Optional)** Specify the TextInput placeholder text Do not use in place of a form label. */
|
|
33
33
|
placeholder?: string
|
|
34
34
|
/** **(Optional)** Specify the SearchBox size. */
|
|
35
35
|
size?: StandardSizes
|
|
@@ -112,8 +112,8 @@ export const SearchBox = ({
|
|
|
112
112
|
id,
|
|
113
113
|
name,
|
|
114
114
|
placeholder,
|
|
115
|
-
size: size as keyof
|
|
116
|
-
type: "search" as keyof
|
|
115
|
+
size: size as keyof TextInputProps["size"],
|
|
116
|
+
type: "search" as keyof TextInputProps["type"],
|
|
117
117
|
...props,
|
|
118
118
|
}
|
|
119
119
|
|
|
@@ -125,7 +125,7 @@ export const SearchBox = ({
|
|
|
125
125
|
</FieldLabel>
|
|
126
126
|
)}
|
|
127
127
|
<div className="coop-search-box--inner">
|
|
128
|
-
<
|
|
128
|
+
<TextInput {...inputProps} />
|
|
129
129
|
<Button {...buttonProps}>{button.label}</Button>
|
|
130
130
|
</div>
|
|
131
131
|
</form>
|
|
@@ -8,38 +8,43 @@ import { FieldError } from "../FieldError"
|
|
|
8
8
|
import { FieldHint } from "../FieldHint"
|
|
9
9
|
import { FieldLabel } from "../FieldLabel"
|
|
10
10
|
|
|
11
|
-
export interface
|
|
11
|
+
export interface TextInputProps
|
|
12
|
+
extends Omit<InputHTMLAttributes<HTMLInputElement>, "size" | "type"> {
|
|
12
13
|
/** **(Optional)** Specify additional CSS classes to be applied to the component. */
|
|
13
14
|
className?: string
|
|
14
|
-
/** **(Optional)** Specify the
|
|
15
|
+
/** **(Optional)** Specify the TextInput error state.
|
|
15
16
|
*
|
|
16
17
|
* This is an instance of `FormFieldError`. You can provide either an object with a `message` key, or a boolean value if you need to render the message independently.
|
|
17
18
|
*/
|
|
18
19
|
error?: FormFieldError
|
|
19
|
-
/** **(Optional)** Specify the
|
|
20
|
+
/** **(Optional)** Specify the TextInput hint.
|
|
20
21
|
*
|
|
21
22
|
* This text is rendered under the label to provide further guidance for users.
|
|
22
23
|
*/
|
|
23
24
|
hint?: string
|
|
24
|
-
/** **(Optional)** Specify the
|
|
25
|
+
/** **(Optional)** Specify the TextInput id. Will be auto-generated if not set. */
|
|
25
26
|
id?: string
|
|
26
|
-
/** **(Optional)** Specify the
|
|
27
|
+
/** **(Optional)** Specify the TextInput label.
|
|
27
28
|
*
|
|
28
29
|
* This property is optional in case you need to render your own label, but all form elements *must* provide a label. */
|
|
29
30
|
label?: string
|
|
30
31
|
/** **(Optional)** Specify whether the label should be visible to humans or screen readers. */
|
|
31
32
|
labelVisible?: boolean
|
|
32
|
-
/** Specify the
|
|
33
|
+
/** Specify the TextInput name. */
|
|
33
34
|
name: string
|
|
34
|
-
/** **(Optional)** Specify the
|
|
35
|
+
/** **(Optional)** Specify the TextInput placeholder text. Do not use in place of a form label. */
|
|
35
36
|
placeholder?: string
|
|
36
|
-
/** **(Optional)** Specify the
|
|
37
|
+
/** **(Optional)** Specify the prefix. */
|
|
38
|
+
prefix?: string
|
|
39
|
+
/** **(Optional)** Specify the TextInput size. */
|
|
37
40
|
size?: StandardSizes
|
|
38
|
-
/** **(Optional)** Specify the
|
|
41
|
+
/** **(Optional)** Specify the suffix. */
|
|
42
|
+
suffix?: string
|
|
43
|
+
/** **(Optional)** Specify the TextInput type. */
|
|
39
44
|
type?: "text" | "email" | "number" | "password" | "search" | "tel" | "url"
|
|
40
45
|
}
|
|
41
46
|
|
|
42
|
-
export const
|
|
47
|
+
export const TextInput = ({
|
|
43
48
|
"aria-placeholder": ariaPlaceholder,
|
|
44
49
|
className,
|
|
45
50
|
error = false,
|
|
@@ -49,17 +54,19 @@ export const Input = ({
|
|
|
49
54
|
labelVisible = true,
|
|
50
55
|
name,
|
|
51
56
|
placeholder,
|
|
57
|
+
prefix,
|
|
52
58
|
size = "md",
|
|
59
|
+
suffix,
|
|
53
60
|
type = "text",
|
|
54
61
|
...props
|
|
55
|
-
}:
|
|
62
|
+
}: TextInputProps): JSX.Element => {
|
|
56
63
|
const internalId = useId()
|
|
57
64
|
|
|
58
65
|
id = id ?? internalId
|
|
59
66
|
|
|
60
67
|
const componentProps = {
|
|
61
68
|
"aria-placeholder": placeholder ?? ariaPlaceholder ?? undefined,
|
|
62
|
-
className: clsx("coop-input", className),
|
|
69
|
+
className: clsx("coop-text-input", className),
|
|
63
70
|
"data-error": error ? "" : undefined,
|
|
64
71
|
"data-size": size.length && size !== "md" ? size : undefined,
|
|
65
72
|
id,
|
|
@@ -70,7 +77,7 @@ export const Input = ({
|
|
|
70
77
|
}
|
|
71
78
|
|
|
72
79
|
return (
|
|
73
|
-
|
|
80
|
+
<div className="coop-form-item">
|
|
74
81
|
{label && (
|
|
75
82
|
<FieldLabel htmlFor={id} isVisible={labelVisible}>
|
|
76
83
|
{label}
|
|
@@ -80,11 +87,13 @@ export const Input = ({
|
|
|
80
87
|
{hint && <FieldHint>{hint}</FieldHint>}
|
|
81
88
|
|
|
82
89
|
{typeof error === "object" && error?.message && <FieldError>{error.message}</FieldError>}
|
|
83
|
-
<div className="coop-
|
|
90
|
+
<div className="coop-text-input-wrapper">
|
|
91
|
+
{prefix && <span className="coop-text-input--prefix">{prefix}</span>}
|
|
84
92
|
<input {...componentProps} />
|
|
93
|
+
{suffix && <span className="coop-text-input--suffix">{suffix}</span>}
|
|
85
94
|
</div>
|
|
86
|
-
|
|
95
|
+
</div>
|
|
87
96
|
)
|
|
88
97
|
}
|
|
89
98
|
|
|
90
|
-
export default
|
|
99
|
+
export default TextInput
|
|
@@ -12,7 +12,7 @@ import { FieldLabel } from "../FieldLabel"
|
|
|
12
12
|
const DEBOUNCE_DELAY = 750
|
|
13
13
|
|
|
14
14
|
const charCountMessage = (remaining: number) => {
|
|
15
|
-
return `You have ${Math.abs(remaining)} ${Math.abs(remaining) === 1 ? "character" : "characters"} ${remaining < 0 ? "too many" : "remaining"}`
|
|
15
|
+
return `You have ${Math.abs(remaining).toLocaleString()} ${Math.abs(remaining) === 1 ? "character" : "characters"} ${remaining < 0 ? "too many" : "remaining"}`
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
export interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {
|
|
@@ -20,6 +20,8 @@ export interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElemen
|
|
|
20
20
|
className?: string
|
|
21
21
|
/** Specify the number of columns (characters per row) in the Textarea. Defaults to `30`. */
|
|
22
22
|
cols?: number
|
|
23
|
+
/** **(Optional)** Specify whether to show the character counter underneath the Textarea. */
|
|
24
|
+
counter?: boolean
|
|
23
25
|
/** **(Optional)** Specify whether the Textarea should allow more characters than its `maxLength` value.
|
|
24
26
|
*
|
|
25
27
|
* Defaults to `false`, meaning users can enter more characters than the maximum but will be warned if they go over the limit. When set to `true`, users will be blocked from typing once they hit the character limit. This can be an accessiblity anti-pattern, so only use this option when absolutely necessary.
|
|
@@ -53,8 +55,6 @@ export interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElemen
|
|
|
53
55
|
placeholder?: string
|
|
54
56
|
/** Specify the number of rows (lines of text) in the Textarea. Defaults to `4`. */
|
|
55
57
|
rows?: number
|
|
56
|
-
/** **(Optional)** Specify whether to show the remaining character count underneath the Textarea. */
|
|
57
|
-
showRemaining?: boolean
|
|
58
58
|
/** **(Optional)** Specify the Textarea size. */
|
|
59
59
|
size?: StandardSizes
|
|
60
60
|
}
|
|
@@ -63,6 +63,7 @@ export const Textarea = ({
|
|
|
63
63
|
"aria-placeholder": ariaPlaceholder,
|
|
64
64
|
className,
|
|
65
65
|
cols = 30,
|
|
66
|
+
counter = false,
|
|
66
67
|
cutoff = false,
|
|
67
68
|
error = false,
|
|
68
69
|
hint,
|
|
@@ -74,7 +75,6 @@ export const Textarea = ({
|
|
|
74
75
|
onChange: userOnChange = undefined,
|
|
75
76
|
placeholder,
|
|
76
77
|
rows = 4,
|
|
77
|
-
showRemaining = false,
|
|
78
78
|
size = "md",
|
|
79
79
|
...props
|
|
80
80
|
}: TextareaProps): JSX.Element => {
|
|
@@ -104,7 +104,7 @@ export const Textarea = ({
|
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
return (
|
|
107
|
-
|
|
107
|
+
<div className="coop-form-item">
|
|
108
108
|
{label && (
|
|
109
109
|
<FieldLabel htmlFor={id} isVisible={labelVisible}>
|
|
110
110
|
{label}
|
|
@@ -114,17 +114,16 @@ export const Textarea = ({
|
|
|
114
114
|
{hint && <FieldHint>{hint}</FieldHint>}
|
|
115
115
|
|
|
116
116
|
{typeof error === "object" && error?.message && <FieldError>{error.message}</FieldError>}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
{showRemaining && maxLength && remaining != null && debouncedRemaining != null && (
|
|
117
|
+
|
|
118
|
+
<textarea
|
|
119
|
+
{...componentProps}
|
|
120
|
+
onChange={(e) => {
|
|
121
|
+
userOnChange?.(e)
|
|
122
|
+
handleChange(e)
|
|
123
|
+
}}
|
|
124
|
+
></textarea>
|
|
125
|
+
|
|
126
|
+
{counter && maxLength && remaining != null && debouncedRemaining != null && (
|
|
128
127
|
<>
|
|
129
128
|
<small
|
|
130
129
|
aria-hidden="true"
|
|
@@ -138,7 +137,7 @@ export const Textarea = ({
|
|
|
138
137
|
</span>
|
|
139
138
|
</>
|
|
140
139
|
)}
|
|
141
|
-
|
|
140
|
+
</div>
|
|
142
141
|
)
|
|
143
142
|
}
|
|
144
143
|
|
package/src/index.ts
CHANGED
|
@@ -2,6 +2,7 @@ export * from "./components/AlertBanner"
|
|
|
2
2
|
export * from "./components/Author"
|
|
3
3
|
export * from "./components/Button"
|
|
4
4
|
export * from "./components/Card"
|
|
5
|
+
export * from "./components/Checkbox"
|
|
5
6
|
export * from "./components/Expandable"
|
|
6
7
|
export * from "./components/Field"
|
|
7
8
|
export * from "./components/FieldError"
|
|
@@ -9,8 +10,8 @@ export * from "./components/FieldHint"
|
|
|
9
10
|
export * from "./components/FieldLabel"
|
|
10
11
|
export * from "./components/Flourish"
|
|
11
12
|
export * from "./components/Image"
|
|
12
|
-
export * from "./components/Input"
|
|
13
13
|
export * from "./components/Pill"
|
|
14
|
+
export * from "./components/RadioButton"
|
|
14
15
|
export * from "./components/RootSVG"
|
|
15
16
|
export * from "./components/SearchBox"
|
|
16
17
|
export * from "./components/Signpost"
|
|
@@ -18,3 +19,4 @@ export * from "./components/SkipNav"
|
|
|
18
19
|
export * from "./components/Squircle"
|
|
19
20
|
export * from "./components/Tag"
|
|
20
21
|
export * from "./components/Textarea"
|
|
22
|
+
export * from "./components/TextInput"
|
package/src/types/index.ts
CHANGED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
2
|
-
import { clsx } from '../../node_modules/clsx/dist/clsx.js';
|
|
3
|
-
import { useId } from 'react';
|
|
4
|
-
import { FieldError } from '../FieldError/FieldError.js';
|
|
5
|
-
import { FieldHint } from '../FieldHint/FieldHint.js';
|
|
6
|
-
import { FieldLabel } from '../FieldLabel/FieldLabel.js';
|
|
7
|
-
|
|
8
|
-
const Input = ({ "aria-placeholder": ariaPlaceholder, className, error = false, hint, id, label, labelVisible = true, name, placeholder, size = "md", type = "text", ...props }) => {
|
|
9
|
-
var _a;
|
|
10
|
-
const internalId = useId();
|
|
11
|
-
id = id !== null && id !== void 0 ? id : internalId;
|
|
12
|
-
const componentProps = {
|
|
13
|
-
"aria-placeholder": (_a = placeholder !== null && placeholder !== void 0 ? placeholder : ariaPlaceholder) !== null && _a !== void 0 ? _a : undefined,
|
|
14
|
-
className: clsx("coop-input", className),
|
|
15
|
-
"data-error": error ? "" : undefined,
|
|
16
|
-
"data-size": size.length && size !== "md" ? size : undefined,
|
|
17
|
-
id,
|
|
18
|
-
name,
|
|
19
|
-
placeholder,
|
|
20
|
-
type,
|
|
21
|
-
...props,
|
|
22
|
-
};
|
|
23
|
-
return (jsxs(Fragment, { children: [label && (jsx(FieldLabel, { htmlFor: id, isVisible: labelVisible, children: label })), hint && jsx(FieldHint, { children: hint }), typeof error === "object" && (error === null || error === void 0 ? void 0 : error.message) && jsx(FieldError, { children: error.message }), jsx("div", { className: "coop-field-control", children: jsx("input", { ...componentProps }) })] }));
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
export { Input, Input as default };
|