@coopdigital/react 0.31.0 → 0.33.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/Field/Field.d.ts +9 -0
- package/dist/components/Field/Field.js +12 -0
- package/dist/components/Field/index.d.ts +4 -0
- package/dist/components/FieldError/FieldError.d.ts +9 -0
- package/dist/components/FieldError/FieldError.js +12 -0
- package/dist/components/FieldError/index.d.ts +4 -0
- package/dist/components/FieldHint/FieldHint.d.ts +9 -0
- package/dist/components/FieldHint/FieldHint.js +12 -0
- package/dist/components/FieldHint/index.d.ts +4 -0
- package/dist/components/FieldLabel/FieldLabel.d.ts +13 -0
- package/dist/components/FieldLabel/FieldLabel.js +13 -0
- package/dist/components/FieldLabel/index.d.ts +4 -0
- package/dist/components/Input/Input.d.ts +31 -0
- package/dist/components/Input/Input.js +26 -0
- package/dist/components/Input/index.d.ts +4 -0
- package/dist/components/Input/index.js +5 -0
- package/dist/components/RootSVG/RootSVG.js +1 -1
- package/dist/components/SearchBox/SearchBox.d.ts +9 -9
- package/dist/components/SearchBox/SearchBox.js +9 -5
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/types/index.d.ts +4 -0
- package/package.json +12 -12
- package/src/components/Field/Field.tsx +20 -0
- package/src/components/Field/index.ts +5 -0
- package/src/components/FieldError/FieldError.tsx +20 -0
- package/src/components/FieldError/index.ts +5 -0
- package/src/components/FieldHint/FieldHint.tsx +25 -0
- package/src/components/FieldHint/index.ts +5 -0
- package/src/components/FieldLabel/FieldLabel.tsx +31 -0
- package/src/components/FieldLabel/index.ts +5 -0
- package/src/components/Input/Input.tsx +87 -0
- package/src/components/Input/index.ts +5 -0
- package/src/components/RootSVG/RootSVG.tsx +1 -1
- package/src/components/SearchBox/SearchBox.tsx +25 -16
- package/src/index.ts +5 -0
- package/src/types/index.ts +2 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { HTMLAttributes, JSX, ReactNode } from "react";
|
|
2
|
+
export interface FieldProps extends HTMLAttributes<HTMLDivElement> {
|
|
3
|
+
/** **(Optional)** Main content inside the component. It can be any valid JSX or string. */
|
|
4
|
+
children?: string | ReactNode;
|
|
5
|
+
/** **(Optional)** Specify additional CSS classes to be applied to the component. */
|
|
6
|
+
className?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare const Field: ({ children, className, ...props }: FieldProps) => JSX.Element;
|
|
9
|
+
export default Field;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { clsx } from '../../node_modules/clsx/dist/clsx.js';
|
|
3
|
+
|
|
4
|
+
const Field = ({ children, className, ...props }) => {
|
|
5
|
+
const componentProps = {
|
|
6
|
+
className: clsx("coop-field ", className),
|
|
7
|
+
...props,
|
|
8
|
+
};
|
|
9
|
+
return jsx("div", { ...componentProps, children: children });
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export { Field, Field as default };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { HTMLAttributes, JSX, ReactNode } from "react";
|
|
2
|
+
export interface FieldErrorProps extends HTMLAttributes<HTMLSpanElement> {
|
|
3
|
+
/** **(Optional)** Main content inside the component. It can be any valid JSX or string. */
|
|
4
|
+
children?: string | ReactNode;
|
|
5
|
+
/** **(Optional)** Specify additional CSS classes to be applied to the component. */
|
|
6
|
+
className?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare const FieldError: ({ children, className, ...props }: FieldErrorProps) => JSX.Element;
|
|
9
|
+
export default FieldError;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { clsx } from '../../node_modules/clsx/dist/clsx.js';
|
|
3
|
+
|
|
4
|
+
const FieldError = ({ children, className, ...props }) => {
|
|
5
|
+
const componentProps = {
|
|
6
|
+
className: clsx("coop-field-error ", className),
|
|
7
|
+
...props,
|
|
8
|
+
};
|
|
9
|
+
return jsx("span", { ...componentProps, children: children });
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export { FieldError, FieldError as default };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { HTMLAttributes, JSX, ReactNode } from "react";
|
|
2
|
+
export interface FieldHintProps extends HTMLAttributes<HTMLParagraphElement> {
|
|
3
|
+
/** Main content inside the component. It can be any valid JSX or string. */
|
|
4
|
+
children: string | ReactNode;
|
|
5
|
+
/** **(Optional)** Specify additional CSS classes to be applied to the component. */
|
|
6
|
+
className?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare const FieldHint: ({ children, className, ...props }: FieldHintProps) => JSX.Element | null;
|
|
9
|
+
export default FieldHint;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { clsx } from '../../node_modules/clsx/dist/clsx.js';
|
|
3
|
+
|
|
4
|
+
const FieldHint = ({ children, className, ...props }) => {
|
|
5
|
+
const componentProps = {
|
|
6
|
+
className: clsx("coop-field-hint ", className),
|
|
7
|
+
...props,
|
|
8
|
+
};
|
|
9
|
+
return children ? jsx("p", { ...componentProps, children: children }) : null;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export { FieldHint, FieldHint as default };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { JSX, LabelHTMLAttributes, ReactNode } from "react";
|
|
2
|
+
export interface FieldLabelProps extends LabelHTMLAttributes<HTMLLabelElement> {
|
|
3
|
+
/** **(Optional)** Main content inside the component. It can be any valid JSX or string. */
|
|
4
|
+
children?: string | ReactNode;
|
|
5
|
+
/** **(Optional)** Specify additional CSS classes to be applied to the component. */
|
|
6
|
+
className?: string;
|
|
7
|
+
/** Specify the field ID to connect FieldLabel to the field itself. */
|
|
8
|
+
htmlFor: string;
|
|
9
|
+
/** **(Optional)** Specify whether the FieldLabel is visible for humans or only for screen readers. */
|
|
10
|
+
isVisible?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare const FieldLabel: ({ children, className, htmlFor, isVisible, ...props }: FieldLabelProps) => JSX.Element | null;
|
|
13
|
+
export default FieldLabel;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { clsx } from '../../node_modules/clsx/dist/clsx.js';
|
|
3
|
+
|
|
4
|
+
const FieldLabel = ({ children, className, htmlFor, isVisible = true, ...props }) => {
|
|
5
|
+
const componentProps = {
|
|
6
|
+
className: clsx("coop-field-label ", isVisible ? "" : "sr-only", className),
|
|
7
|
+
htmlFor,
|
|
8
|
+
...props,
|
|
9
|
+
};
|
|
10
|
+
return children && htmlFor ? jsx("label", { ...componentProps, children: children }) : null;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export { FieldLabel, FieldLabel as default };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { InputHTMLAttributes, JSX } from "react";
|
|
2
|
+
import { FormFieldError, StandardSizes } from "../../../src/types";
|
|
3
|
+
export interface InputProps 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 Input error. */
|
|
7
|
+
error?: FormFieldError;
|
|
8
|
+
/** **(Optional)** Specify the Input hint.
|
|
9
|
+
*
|
|
10
|
+
* This text is rendered under the label to provide further guidance for users.
|
|
11
|
+
*/
|
|
12
|
+
hint?: string;
|
|
13
|
+
/** **(Optional)** Specify the Input id. Will be auto-generated if not set. */
|
|
14
|
+
id?: string;
|
|
15
|
+
/** **(Optional)** Specify the Input label.
|
|
16
|
+
*
|
|
17
|
+
* This property is optional in case you need to render your own label, but all form elements *must* provide a label. */
|
|
18
|
+
label?: string;
|
|
19
|
+
/** **(Optional)** Specify whether the label should be visible to humans or screen readers. */
|
|
20
|
+
labelVisible?: boolean;
|
|
21
|
+
/** Specify the Input name. */
|
|
22
|
+
name: string;
|
|
23
|
+
/** **(Optional)** Specify the Input placeholder text. Do not use in place of a form label. */
|
|
24
|
+
placeholder?: string;
|
|
25
|
+
/** **(Optional)** Specify the Input size. */
|
|
26
|
+
size?: StandardSizes;
|
|
27
|
+
/** **(Optional)** Specify the Input type. */
|
|
28
|
+
type?: "text" | "email" | "number" | "password" | "search" | "tel" | "url";
|
|
29
|
+
}
|
|
30
|
+
export declare const Input: ({ "aria-placeholder": ariaPlaceholder, className, error, hint, id, label, labelVisible, name, placeholder, size, type, ...props }: InputProps) => JSX.Element;
|
|
31
|
+
export default Input;
|
|
@@ -0,0 +1,26 @@
|
|
|
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 };
|
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import { StandardSizes } from "src/types";
|
|
1
|
+
import type { InputHTMLAttributes, JSX } from "react";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { StandardSizes } from "../../../src/types";
|
|
4
4
|
import { type ButtonProps } from "../Button";
|
|
5
|
-
export interface SearchBoxProps extends
|
|
5
|
+
export interface SearchBoxProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "size" | "type"> {
|
|
6
6
|
/** **(Optional)** Specify a server endpoint to submit the form. Will be ignored if onSubmit is also set. */
|
|
7
7
|
action?: string;
|
|
8
|
-
/** **(Optional)** Specify whether or not to enable autocomplete on the input field. Default: `off`. */
|
|
9
|
-
autoComplete?: "off" | "on";
|
|
10
8
|
/** **(Optional)** Specify props to forward to the Button element. Use `label` to set Button text. */
|
|
11
9
|
button?: Pick<ButtonProps, "className" | "loadingText"> & {
|
|
12
10
|
label?: React.ReactNode;
|
|
13
11
|
};
|
|
14
12
|
/** **(Optional)** Specify additional CSS classes to be applied to the component. */
|
|
15
13
|
className?: string;
|
|
14
|
+
/** **(Optional)** Specify the Input id. Will be auto-generated if not set. */
|
|
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 name
|
|
20
|
+
/** **(Optional)** Specify the Input 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 placeholder text
|
|
24
|
+
/** **(Optional)** Specify the Input 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;
|
|
28
28
|
/** **(Optional)** Specify the SearchBox variant. */
|
|
29
29
|
variant?: "green" | "blue" | "white" | "grey" | "green-ghost" | "blue-ghost" | "white-ghost" | "grey-ghost";
|
|
30
30
|
}
|
|
31
|
-
export declare const SearchBox: ({ action, "aria-placeholder": ariaPlaceholder, autoCapitalize, autoComplete, button, className, label, labelVisible, name, onSubmit, placeholder, size, variant, ...props }: SearchBoxProps) => JSX.Element;
|
|
31
|
+
export declare const SearchBox: ({ action, "aria-placeholder": ariaPlaceholder, autoCapitalize, autoComplete, button, className, id, label, labelVisible, name, onSubmit, placeholder, size, variant, ...props }: SearchBoxProps) => JSX.Element;
|
|
32
32
|
export default SearchBox;
|
|
@@ -2,17 +2,21 @@
|
|
|
2
2
|
"use client";
|
|
3
3
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
4
4
|
import { clsx } from '../../node_modules/clsx/dist/clsx.js';
|
|
5
|
-
import React, { useState,
|
|
5
|
+
import React, { useState, useId, useCallback } from 'react';
|
|
6
6
|
import { Button } from '../Button/Button.js';
|
|
7
|
+
import { FieldLabel } from '../FieldLabel/FieldLabel.js';
|
|
7
8
|
import { SearchIcon } from '../Icon/SearchIcon.js';
|
|
9
|
+
import { Input } from '../Input/Input.js';
|
|
8
10
|
|
|
9
11
|
const defaultButtonProps = {
|
|
10
12
|
label: React.createElement(SearchIcon, { alt: "Search", stroke: "currentColor", strokeWidth: 2 }),
|
|
11
13
|
loadingText: "",
|
|
12
14
|
};
|
|
13
|
-
const SearchBox = ({ action, "aria-placeholder": ariaPlaceholder, autoCapitalize = "off", autoComplete = "off", button = defaultButtonProps, className, label, labelVisible = false, name = "query", onSubmit, placeholder, size = "md", variant = "green", ...props }) => {
|
|
15
|
+
const SearchBox = ({ action, "aria-placeholder": ariaPlaceholder, autoCapitalize = "off", autoComplete = "off", button = defaultButtonProps, className, id, label, labelVisible = false, name = "query", onSubmit, placeholder, size = "md", variant = "green", ...props }) => {
|
|
14
16
|
var _a, _b;
|
|
15
17
|
const [isPending, setIsPending] = useState(false);
|
|
18
|
+
const internalId = useId();
|
|
19
|
+
id = id !== null && id !== void 0 ? id : internalId;
|
|
16
20
|
const handleSubmit = useCallback(async (event) => {
|
|
17
21
|
event.preventDefault();
|
|
18
22
|
if (isPending || !onSubmit)
|
|
@@ -25,11 +29,10 @@ const SearchBox = ({ action, "aria-placeholder": ariaPlaceholder, autoCapitalize
|
|
|
25
29
|
setIsPending(false);
|
|
26
30
|
}
|
|
27
31
|
}, [onSubmit, isPending]);
|
|
28
|
-
const id = useId();
|
|
29
32
|
const formProps = {
|
|
30
33
|
action: action !== null && action !== void 0 ? action : undefined,
|
|
31
34
|
className: clsx("coop-search-box", className),
|
|
32
|
-
"data-size": size
|
|
35
|
+
//"data-size": size && size !== "md" ? size : undefined,
|
|
33
36
|
"data-variant": variant.length && variant !== "green" ? variant : undefined,
|
|
34
37
|
onSubmit: onSubmit ? handleSubmit : undefined,
|
|
35
38
|
};
|
|
@@ -47,10 +50,11 @@ const SearchBox = ({ action, "aria-placeholder": ariaPlaceholder, autoCapitalize
|
|
|
47
50
|
id,
|
|
48
51
|
name,
|
|
49
52
|
placeholder,
|
|
53
|
+
size: size,
|
|
50
54
|
type: "search",
|
|
51
55
|
...props,
|
|
52
56
|
};
|
|
53
|
-
return (jsxs("form", { ...formProps, 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(Input, { ...inputProps }), jsx(Button, { ...buttonProps, children: button.label })] })] }));
|
|
54
58
|
};
|
|
55
59
|
|
|
56
60
|
export { SearchBox, SearchBox as default };
|
package/dist/index.d.ts
CHANGED
|
@@ -3,8 +3,13 @@ export * from "./components/Author";
|
|
|
3
3
|
export * from "./components/Button";
|
|
4
4
|
export * from "./components/Card";
|
|
5
5
|
export * from "./components/Expandable";
|
|
6
|
+
export * from "./components/Field";
|
|
7
|
+
export * from "./components/FieldError";
|
|
8
|
+
export * from "./components/FieldHint";
|
|
9
|
+
export * from "./components/FieldLabel";
|
|
6
10
|
export * from "./components/Flourish";
|
|
7
11
|
export * from "./components/Image";
|
|
12
|
+
export * from "./components/Input";
|
|
8
13
|
export * from "./components/Pill";
|
|
9
14
|
export * from "./components/RootSVG";
|
|
10
15
|
export * from "./components/SearchBox";
|
package/dist/index.js
CHANGED
|
@@ -3,8 +3,13 @@ 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
5
|
export { Expandable } from './components/Expandable/Expandable.js';
|
|
6
|
+
export { Field } from './components/Field/Field.js';
|
|
7
|
+
export { FieldError } from './components/FieldError/FieldError.js';
|
|
8
|
+
export { FieldHint } from './components/FieldHint/FieldHint.js';
|
|
9
|
+
export { FieldLabel } from './components/FieldLabel/FieldLabel.js';
|
|
6
10
|
export { Flourish } from './components/Flourish/Flourish.js';
|
|
7
11
|
export { Image } from './components/Image/Image.js';
|
|
12
|
+
export { Input } from './components/Input/Input.js';
|
|
8
13
|
export { Pill } from './components/Pill/Pill.js';
|
|
9
14
|
export { RootSVG } from './components/RootSVG/RootSVG.js';
|
|
10
15
|
export { SearchBox } from './components/SearchBox/SearchBox.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.33.0",
|
|
5
5
|
"private": false,
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"access": "public"
|
|
@@ -56,20 +56,20 @@
|
|
|
56
56
|
"description": "",
|
|
57
57
|
"devDependencies": {
|
|
58
58
|
"@axe-core/playwright": "^4.10.2",
|
|
59
|
-
"@playwright/test": "^1.
|
|
60
|
-
"@storybook/addon-a11y": "^9.1.
|
|
61
|
-
"@storybook/addon-docs": "^9.1.
|
|
62
|
-
"@storybook/addon-onboarding": "^9.1.
|
|
63
|
-
"@storybook/react-vite": "^9.1.
|
|
64
|
-
"@testing-library/jest-dom": "^6.
|
|
59
|
+
"@playwright/test": "^1.55.0",
|
|
60
|
+
"@storybook/addon-a11y": "^9.1.3",
|
|
61
|
+
"@storybook/addon-docs": "^9.1.3",
|
|
62
|
+
"@storybook/addon-onboarding": "^9.1.3",
|
|
63
|
+
"@storybook/react-vite": "^9.1.3",
|
|
64
|
+
"@testing-library/jest-dom": "^6.8.0",
|
|
65
65
|
"@testing-library/react": "^16.3.0",
|
|
66
|
-
"@types/react": "^19.1.
|
|
67
|
-
"@types/react-dom": "^19.1.
|
|
66
|
+
"@types/react": "^19.1.12",
|
|
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
71
|
"serve": "^14.2.4",
|
|
72
|
-
"storybook": "^9.1.
|
|
72
|
+
"storybook": "^9.1.3"
|
|
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.29.0"
|
|
84
84
|
},
|
|
85
|
-
"gitHead": "
|
|
85
|
+
"gitHead": "b7f3df204e1f4e38b3c978af0506243b30365b4a"
|
|
86
86
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { HTMLAttributes, JSX, ReactNode } from "react"
|
|
2
|
+
|
|
3
|
+
import clsx from "clsx"
|
|
4
|
+
|
|
5
|
+
export interface FieldProps extends HTMLAttributes<HTMLDivElement> {
|
|
6
|
+
/** **(Optional)** Main content inside the component. It can be any valid JSX or string. */
|
|
7
|
+
children?: string | ReactNode
|
|
8
|
+
/** **(Optional)** Specify additional CSS classes to be applied to the component. */
|
|
9
|
+
className?: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const Field = ({ children, className, ...props }: FieldProps): JSX.Element => {
|
|
13
|
+
const componentProps = {
|
|
14
|
+
className: clsx("coop-field ", className),
|
|
15
|
+
...props,
|
|
16
|
+
}
|
|
17
|
+
return <div {...componentProps}>{children}</div>
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default Field
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { HTMLAttributes, JSX, ReactNode } from "react"
|
|
2
|
+
|
|
3
|
+
import clsx from "clsx"
|
|
4
|
+
|
|
5
|
+
export interface FieldErrorProps extends HTMLAttributes<HTMLSpanElement> {
|
|
6
|
+
/** **(Optional)** Main content inside the component. It can be any valid JSX or string. */
|
|
7
|
+
children?: string | ReactNode
|
|
8
|
+
/** **(Optional)** Specify additional CSS classes to be applied to the component. */
|
|
9
|
+
className?: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const FieldError = ({ children, className, ...props }: FieldErrorProps): JSX.Element => {
|
|
13
|
+
const componentProps = {
|
|
14
|
+
className: clsx("coop-field-error ", className),
|
|
15
|
+
...props,
|
|
16
|
+
}
|
|
17
|
+
return <span {...componentProps}>{children}</span>
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default FieldError
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { HTMLAttributes, JSX, ReactNode } from "react"
|
|
2
|
+
|
|
3
|
+
import clsx from "clsx"
|
|
4
|
+
|
|
5
|
+
export interface FieldHintProps extends HTMLAttributes<HTMLParagraphElement> {
|
|
6
|
+
/** Main content inside the component. It can be any valid JSX or string. */
|
|
7
|
+
children: string | ReactNode
|
|
8
|
+
/** **(Optional)** Specify additional CSS classes to be applied to the component. */
|
|
9
|
+
className?: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const FieldHint = ({
|
|
13
|
+
children,
|
|
14
|
+
className,
|
|
15
|
+
...props
|
|
16
|
+
}: FieldHintProps): JSX.Element | null => {
|
|
17
|
+
const componentProps = {
|
|
18
|
+
className: clsx("coop-field-hint ", className),
|
|
19
|
+
...props,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return children ? <p {...componentProps}>{children}</p> : null
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export default FieldHint
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { JSX, LabelHTMLAttributes, ReactNode } from "react"
|
|
2
|
+
|
|
3
|
+
import clsx from "clsx"
|
|
4
|
+
|
|
5
|
+
export interface FieldLabelProps extends LabelHTMLAttributes<HTMLLabelElement> {
|
|
6
|
+
/** **(Optional)** Main content inside the component. It can be any valid JSX or string. */
|
|
7
|
+
children?: string | ReactNode
|
|
8
|
+
/** **(Optional)** Specify additional CSS classes to be applied to the component. */
|
|
9
|
+
className?: string
|
|
10
|
+
/** Specify the field ID to connect FieldLabel to the field itself. */
|
|
11
|
+
htmlFor: string
|
|
12
|
+
/** **(Optional)** Specify whether the FieldLabel is visible for humans or only for screen readers. */
|
|
13
|
+
isVisible?: boolean
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const FieldLabel = ({
|
|
17
|
+
children,
|
|
18
|
+
className,
|
|
19
|
+
htmlFor,
|
|
20
|
+
isVisible = true,
|
|
21
|
+
...props
|
|
22
|
+
}: FieldLabelProps): JSX.Element | null => {
|
|
23
|
+
const componentProps = {
|
|
24
|
+
className: clsx("coop-field-label ", isVisible ? "" : "sr-only", className),
|
|
25
|
+
htmlFor,
|
|
26
|
+
...props,
|
|
27
|
+
}
|
|
28
|
+
return children && htmlFor ? <label {...componentProps}>{children}</label> : null
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export default FieldLabel
|
|
@@ -0,0 +1,87 @@
|
|
|
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 InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "size" | "type"> {
|
|
12
|
+
/** **(Optional)** Specify additional CSS classes to be applied to the component. */
|
|
13
|
+
className?: string
|
|
14
|
+
/** **(Optional)** Specify the Input error. */
|
|
15
|
+
error?: FormFieldError
|
|
16
|
+
/** **(Optional)** Specify the Input hint.
|
|
17
|
+
*
|
|
18
|
+
* This text is rendered under the label to provide further guidance for users.
|
|
19
|
+
*/
|
|
20
|
+
hint?: string
|
|
21
|
+
/** **(Optional)** Specify the Input id. Will be auto-generated if not set. */
|
|
22
|
+
id?: string
|
|
23
|
+
/** **(Optional)** Specify the Input label.
|
|
24
|
+
*
|
|
25
|
+
* This property is optional in case you need to render your own label, but all form elements *must* provide a label. */
|
|
26
|
+
label?: string
|
|
27
|
+
/** **(Optional)** Specify whether the label should be visible to humans or screen readers. */
|
|
28
|
+
labelVisible?: boolean
|
|
29
|
+
/** Specify the Input name. */
|
|
30
|
+
name: string
|
|
31
|
+
/** **(Optional)** Specify the Input placeholder text. Do not use in place of a form label. */
|
|
32
|
+
placeholder?: string
|
|
33
|
+
/** **(Optional)** Specify the Input size. */
|
|
34
|
+
size?: StandardSizes
|
|
35
|
+
/** **(Optional)** Specify the Input type. */
|
|
36
|
+
type?: "text" | "email" | "number" | "password" | "search" | "tel" | "url"
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const Input = ({
|
|
40
|
+
"aria-placeholder": ariaPlaceholder,
|
|
41
|
+
className,
|
|
42
|
+
error = false,
|
|
43
|
+
hint,
|
|
44
|
+
id,
|
|
45
|
+
label,
|
|
46
|
+
labelVisible = true,
|
|
47
|
+
name,
|
|
48
|
+
placeholder,
|
|
49
|
+
size = "md",
|
|
50
|
+
type = "text",
|
|
51
|
+
...props
|
|
52
|
+
}: InputProps): JSX.Element => {
|
|
53
|
+
const internalId = useId()
|
|
54
|
+
|
|
55
|
+
id = id ?? internalId
|
|
56
|
+
|
|
57
|
+
const componentProps = {
|
|
58
|
+
"aria-placeholder": placeholder ?? ariaPlaceholder ?? undefined,
|
|
59
|
+
className: clsx("coop-input", className),
|
|
60
|
+
"data-error": error ? "" : undefined,
|
|
61
|
+
"data-size": size.length && size !== "md" ? size : undefined,
|
|
62
|
+
id,
|
|
63
|
+
name,
|
|
64
|
+
placeholder,
|
|
65
|
+
type,
|
|
66
|
+
...props,
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return (
|
|
70
|
+
<>
|
|
71
|
+
{label && (
|
|
72
|
+
<FieldLabel htmlFor={id} isVisible={labelVisible}>
|
|
73
|
+
{label}
|
|
74
|
+
</FieldLabel>
|
|
75
|
+
)}
|
|
76
|
+
|
|
77
|
+
{hint && <FieldHint>{hint}</FieldHint>}
|
|
78
|
+
|
|
79
|
+
{typeof error === "object" && error?.message && <FieldError>{error.message}</FieldError>}
|
|
80
|
+
<div className="coop-field-control">
|
|
81
|
+
<input {...componentProps} />
|
|
82
|
+
</div>
|
|
83
|
+
</>
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export default Input
|
|
@@ -1,31 +1,35 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
|
+
import type { InputHTMLAttributes, JSX } from "react"
|
|
4
|
+
|
|
3
5
|
import clsx from "clsx"
|
|
4
|
-
import React, {
|
|
5
|
-
import { type JSX } from "react"
|
|
6
|
-
import { StandardSizes } from "src/types"
|
|
6
|
+
import React, { useCallback, useId, useState } from "react"
|
|
7
7
|
|
|
8
|
+
import { StandardSizes } from "../../../src/types"
|
|
8
9
|
import { Button, type ButtonProps } from "../Button"
|
|
10
|
+
import { FieldLabel } from "../FieldLabel"
|
|
9
11
|
import { SearchIcon } from "../Icon"
|
|
12
|
+
import Input, { InputProps } from "../Input"
|
|
10
13
|
|
|
11
|
-
export interface SearchBoxProps
|
|
14
|
+
export interface SearchBoxProps
|
|
15
|
+
extends Omit<InputHTMLAttributes<HTMLInputElement>, "size" | "type"> {
|
|
12
16
|
/** **(Optional)** Specify a server endpoint to submit the form. Will be ignored if onSubmit is also set. */
|
|
13
17
|
action?: string
|
|
14
|
-
/** **(Optional)** Specify whether or not to enable autocomplete on the input field. Default: `off`. */
|
|
15
|
-
autoComplete?: "off" | "on"
|
|
16
18
|
/** **(Optional)** Specify props to forward to the Button element. Use `label` to set Button text. */
|
|
17
19
|
button?: Pick<ButtonProps, "className" | "loadingText"> & { label?: React.ReactNode }
|
|
18
20
|
/** **(Optional)** Specify additional CSS classes to be applied to the component. */
|
|
19
21
|
className?: string
|
|
22
|
+
/** **(Optional)** Specify the Input id. Will be auto-generated if not set. */
|
|
23
|
+
id?: string
|
|
20
24
|
/** Specify the label displayed above the search field. Hidden by default, but visible to screen readers. */
|
|
21
25
|
label: string
|
|
22
26
|
/** **(Optional)** Specify whether the label should be visible to humans or screenreaders. */
|
|
23
27
|
labelVisible?: boolean
|
|
24
|
-
/** **(Optional)** Specify the name
|
|
28
|
+
/** **(Optional)** Specify the Input name, also used as the URL search parameter. Defaults to `query`. */
|
|
25
29
|
name?: string
|
|
26
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. */
|
|
27
31
|
onSubmit?: React.FormEventHandler<HTMLElement> | undefined
|
|
28
|
-
/** **(Optional)** Specify placeholder text
|
|
32
|
+
/** **(Optional)** Specify the Input placeholder text Do not use in place of a form label. */
|
|
29
33
|
placeholder?: string
|
|
30
34
|
/** **(Optional)** Specify the SearchBox size. */
|
|
31
35
|
size?: StandardSizes
|
|
@@ -53,6 +57,7 @@ export const SearchBox = ({
|
|
|
53
57
|
autoComplete = "off",
|
|
54
58
|
button = defaultButtonProps,
|
|
55
59
|
className,
|
|
60
|
+
id,
|
|
56
61
|
label,
|
|
57
62
|
labelVisible = false,
|
|
58
63
|
name = "query",
|
|
@@ -63,6 +68,9 @@ export const SearchBox = ({
|
|
|
63
68
|
...props
|
|
64
69
|
}: SearchBoxProps): JSX.Element => {
|
|
65
70
|
const [isPending, setIsPending] = useState(false)
|
|
71
|
+
const internalId = useId()
|
|
72
|
+
|
|
73
|
+
id = id ?? internalId
|
|
66
74
|
|
|
67
75
|
const handleSubmit = useCallback(
|
|
68
76
|
async (event: React.FormEvent<HTMLFormElement>) => {
|
|
@@ -81,12 +89,10 @@ export const SearchBox = ({
|
|
|
81
89
|
[onSubmit, isPending]
|
|
82
90
|
)
|
|
83
91
|
|
|
84
|
-
const id = useId()
|
|
85
|
-
|
|
86
92
|
const formProps = {
|
|
87
93
|
action: action ?? undefined,
|
|
88
94
|
className: clsx("coop-search-box", className),
|
|
89
|
-
"data-size": size
|
|
95
|
+
//"data-size": size && size !== "md" ? size : undefined,
|
|
90
96
|
"data-variant": variant.length && variant !== "green" ? variant : undefined,
|
|
91
97
|
onSubmit: onSubmit ? handleSubmit : undefined,
|
|
92
98
|
}
|
|
@@ -106,17 +112,20 @@ export const SearchBox = ({
|
|
|
106
112
|
id,
|
|
107
113
|
name,
|
|
108
114
|
placeholder,
|
|
109
|
-
|
|
115
|
+
size: size as keyof InputProps["size"],
|
|
116
|
+
type: "search" as keyof InputProps["type"],
|
|
110
117
|
...props,
|
|
111
118
|
}
|
|
112
119
|
|
|
113
120
|
return (
|
|
114
121
|
<form {...formProps}>
|
|
115
|
-
|
|
116
|
-
{
|
|
117
|
-
|
|
122
|
+
{label && (
|
|
123
|
+
<FieldLabel htmlFor={id} isVisible={labelVisible}>
|
|
124
|
+
{label}
|
|
125
|
+
</FieldLabel>
|
|
126
|
+
)}
|
|
118
127
|
<div className="coop-search-box--inner">
|
|
119
|
-
<
|
|
128
|
+
<Input {...inputProps} />
|
|
120
129
|
<Button {...buttonProps}>{button.label}</Button>
|
|
121
130
|
</div>
|
|
122
131
|
</form>
|
package/src/index.ts
CHANGED
|
@@ -3,8 +3,13 @@ export * from "./components/Author"
|
|
|
3
3
|
export * from "./components/Button"
|
|
4
4
|
export * from "./components/Card"
|
|
5
5
|
export * from "./components/Expandable"
|
|
6
|
+
export * from "./components/Field"
|
|
7
|
+
export * from "./components/FieldError"
|
|
8
|
+
export * from "./components/FieldHint"
|
|
9
|
+
export * from "./components/FieldLabel"
|
|
6
10
|
export * from "./components/Flourish"
|
|
7
11
|
export * from "./components/Image"
|
|
12
|
+
export * from "./components/Input"
|
|
8
13
|
export * from "./components/Pill"
|
|
9
14
|
export * from "./components/RootSVG"
|
|
10
15
|
export * from "./components/SearchBox"
|
package/src/types/index.ts
CHANGED