@coopdigital/react 0.30.2 → 0.32.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/Flourish/Flourish.d.ts +12 -0
- package/dist/components/Flourish/Flourish.js +13 -0
- package/dist/components/Flourish/index.d.ts +4 -0
- package/dist/components/Input/Input.d.ts +32 -0
- package/dist/components/Input/Input.js +23 -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 +8 -5
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/package.json +11 -11
- package/src/components/Flourish/Flourish.tsx +38 -0
- package/src/components/Flourish/index.ts +5 -0
- package/src/components/Input/Input.tsx +77 -0
- package/src/components/Input/index.ts +5 -0
- package/src/components/RootSVG/RootSVG.tsx +1 -1
- package/src/components/SearchBox/SearchBox.tsx +19 -13
- package/src/index.ts +2 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { JSX, ReactNode, SVGProps } from "react";
|
|
2
|
+
import { Darks, Lights } from "../../types/colors";
|
|
3
|
+
export interface FlourishProps extends SVGProps<SVGSVGElement> {
|
|
4
|
+
/** Specify the text to be highlighted by the Flourish. */
|
|
5
|
+
children: string | ReactNode;
|
|
6
|
+
/** **(Optional)** Specify additional CSS classes to be applied to the component. */
|
|
7
|
+
className?: string;
|
|
8
|
+
/** **(Optional)** Specify the Flourish color. */
|
|
9
|
+
fill?: Darks | Lights;
|
|
10
|
+
}
|
|
11
|
+
export declare const Flourish: ({ children, className, fill, ...props }: FlourishProps) => JSX.Element;
|
|
12
|
+
export default Flourish;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { clsx } from '../../node_modules/clsx/dist/clsx.js';
|
|
3
|
+
|
|
4
|
+
const Flourish = ({ children, className, fill = "light-yellow", ...props }) => {
|
|
5
|
+
const componentProps = {
|
|
6
|
+
className: clsx("coop-flourish ", className),
|
|
7
|
+
fill: `var(--color-${fill})`,
|
|
8
|
+
...props,
|
|
9
|
+
};
|
|
10
|
+
return (jsxs("span", { style: { position: "relative" }, children: [children, jsx("svg", { ...componentProps, height: "10", viewBox: "0 0 276 10", width: "276", children: jsx("path", { d: "M275.9 8.6c.1-1.6.2-1.8-.4-2.9.3-1-.3-1.2-1.8-1.1v-.3c.6-.4.2-.2 1.4-.1-.9-2.3-5.6-1.8-8.5-2.3C259 .5 246.3.7 237.4.5L185 .4l-33-.2-26.1-.2-67.4 1.2-44.3.5C10.7 2.1 1.5.4 0 3.3l1 .2L0 4v.5C8.2 7.9 26.6 7.2 35.6 7c5 0 13.5 1.6 16.5-.6C53.4 8 59.5 8 62 7.7l45 .1 42.8.3 30.7.3 44.2.6 27.8-.5 23 .8c.1-.8-.3-.5.5-.7ZM219 2.8v-.2l.8-.2h.4l.3.4H219Zm30-.1h1.2c-.8.4-.5.3-1.2 0Zm6.2.6.2-.4h.3l-.5.4Z" }) })] }));
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export { Flourish, Flourish as default };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { InputHTMLAttributes, JSX } from "react";
|
|
2
|
+
import { 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 message. */
|
|
7
|
+
error?: {
|
|
8
|
+
message: string;
|
|
9
|
+
type?: string;
|
|
10
|
+
} | false | null | undefined;
|
|
11
|
+
/** **(Optional)** Specify the Input hint.
|
|
12
|
+
*
|
|
13
|
+
* This text is rendered under the label to provide further guidance for users.
|
|
14
|
+
*/
|
|
15
|
+
hint?: string;
|
|
16
|
+
/** **(Optional)** Specify the Input id. Will be auto-generated if not set. */
|
|
17
|
+
id?: string;
|
|
18
|
+
/** **(Optional)** Specify the Input 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
|
+
/** Specify the Input name. */
|
|
23
|
+
name: string;
|
|
24
|
+
/** **(Optional)** Specify the Input placeholder text. Do not use in place of a form label. */
|
|
25
|
+
placeholder?: string;
|
|
26
|
+
/** **(Optional)** Specify the Input size. */
|
|
27
|
+
size?: StandardSizes;
|
|
28
|
+
/** **(Optional)** Specify the Input type. */
|
|
29
|
+
type?: "text" | "email" | "number" | "password" | "search" | "tel" | "url";
|
|
30
|
+
}
|
|
31
|
+
export declare const Input: ({ "aria-placeholder": ariaPlaceholder, className, error, hint, id, label, name, placeholder, size, type, ...props }: InputProps) => JSX.Element;
|
|
32
|
+
export default Input;
|
|
@@ -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
|
+
|
|
5
|
+
const Input = ({ "aria-placeholder": ariaPlaceholder, className, error = false, hint, id, label, name, placeholder, size = "md", type = "text", ...props }) => {
|
|
6
|
+
var _a;
|
|
7
|
+
const internalId = useId();
|
|
8
|
+
id = id !== null && id !== void 0 ? id : internalId;
|
|
9
|
+
const componentProps = {
|
|
10
|
+
"aria-placeholder": (_a = placeholder !== null && placeholder !== void 0 ? placeholder : ariaPlaceholder) !== null && _a !== void 0 ? _a : undefined,
|
|
11
|
+
className: clsx("coop-input", className),
|
|
12
|
+
"data-error": error ? "" : undefined,
|
|
13
|
+
"data-size": size.length && size !== "md" ? size : undefined,
|
|
14
|
+
id,
|
|
15
|
+
name,
|
|
16
|
+
placeholder,
|
|
17
|
+
type,
|
|
18
|
+
...props,
|
|
19
|
+
};
|
|
20
|
+
return (jsxs("div", { className: "coop-field", children: [label && (jsx("label", { className: "coop-form--label", htmlFor: id, children: label })), hint && jsx("p", { className: "coop-form--hint", children: hint }), error && jsx("span", { className: "coop-form--error", children: error.message }), jsx("input", { ...componentProps })] }));
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
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,20 @@
|
|
|
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
7
|
import { SearchIcon } from '../Icon/SearchIcon.js';
|
|
8
|
+
import { Input } from '../Input/Input.js';
|
|
8
9
|
|
|
9
10
|
const defaultButtonProps = {
|
|
10
11
|
label: React.createElement(SearchIcon, { alt: "Search", stroke: "currentColor", strokeWidth: 2 }),
|
|
11
12
|
loadingText: "",
|
|
12
13
|
};
|
|
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 }) => {
|
|
14
|
+
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
15
|
var _a, _b;
|
|
15
16
|
const [isPending, setIsPending] = useState(false);
|
|
17
|
+
const internalId = useId();
|
|
18
|
+
id = id !== null && id !== void 0 ? id : internalId;
|
|
16
19
|
const handleSubmit = useCallback(async (event) => {
|
|
17
20
|
event.preventDefault();
|
|
18
21
|
if (isPending || !onSubmit)
|
|
@@ -25,11 +28,10 @@ const SearchBox = ({ action, "aria-placeholder": ariaPlaceholder, autoCapitalize
|
|
|
25
28
|
setIsPending(false);
|
|
26
29
|
}
|
|
27
30
|
}, [onSubmit, isPending]);
|
|
28
|
-
const id = useId();
|
|
29
31
|
const formProps = {
|
|
30
32
|
action: action !== null && action !== void 0 ? action : undefined,
|
|
31
33
|
className: clsx("coop-search-box", className),
|
|
32
|
-
"data-size": size
|
|
34
|
+
//"data-size": size && size !== "md" ? size : undefined,
|
|
33
35
|
"data-variant": variant.length && variant !== "green" ? variant : undefined,
|
|
34
36
|
onSubmit: onSubmit ? handleSubmit : undefined,
|
|
35
37
|
};
|
|
@@ -47,10 +49,11 @@ const SearchBox = ({ action, "aria-placeholder": ariaPlaceholder, autoCapitalize
|
|
|
47
49
|
id,
|
|
48
50
|
name,
|
|
49
51
|
placeholder,
|
|
52
|
+
size: size,
|
|
50
53
|
type: "search",
|
|
51
54
|
...props,
|
|
52
55
|
};
|
|
53
|
-
return (jsxs("form", { ...formProps, children: [jsx("label", { className: labelVisible ? "" : "sr-only", htmlFor: id, children: label }), jsxs("div", { className: "coop-search-box--inner", children: [jsx(
|
|
56
|
+
return (jsxs("form", { ...formProps, children: [jsx("label", { className: labelVisible ? "" : "sr-only", htmlFor: id, children: label }), jsxs("div", { className: "coop-search-box--inner", children: [jsx(Input, { ...inputProps }), jsx(Button, { ...buttonProps, children: button.label })] })] }));
|
|
54
57
|
};
|
|
55
58
|
|
|
56
59
|
export { SearchBox, SearchBox as default };
|
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,9 @@ 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/Flourish";
|
|
6
7
|
export * from "./components/Image";
|
|
8
|
+
export * from "./components/Input";
|
|
7
9
|
export * from "./components/Pill";
|
|
8
10
|
export * from "./components/RootSVG";
|
|
9
11
|
export * from "./components/SearchBox";
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,9 @@ 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 { Flourish } from './components/Flourish/Flourish.js';
|
|
6
7
|
export { Image } from './components/Image/Image.js';
|
|
8
|
+
export { Input } from './components/Input/Input.js';
|
|
7
9
|
export { Pill } from './components/Pill/Pill.js';
|
|
8
10
|
export { RootSVG } from './components/RootSVG/RootSVG.js';
|
|
9
11
|
export { SearchBox } from './components/SearchBox/SearchBox.js';
|
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.32.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.
|
|
66
|
+
"@types/react": "^19.1.10",
|
|
67
67
|
"@types/react-dom": "^19.1.7",
|
|
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.28.0"
|
|
84
84
|
},
|
|
85
|
-
"gitHead": "
|
|
85
|
+
"gitHead": "dfdb5d4d591c47722d4969c5221a3e389d8a4fab"
|
|
86
86
|
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { JSX, ReactNode, SVGProps } from "react"
|
|
2
|
+
|
|
3
|
+
import clsx from "clsx"
|
|
4
|
+
|
|
5
|
+
import { Darks, Lights } from "../../types/colors"
|
|
6
|
+
|
|
7
|
+
export interface FlourishProps extends SVGProps<SVGSVGElement> {
|
|
8
|
+
/** Specify the text to be highlighted by the Flourish. */
|
|
9
|
+
children: string | ReactNode
|
|
10
|
+
/** **(Optional)** Specify additional CSS classes to be applied to the component. */
|
|
11
|
+
className?: string
|
|
12
|
+
/** **(Optional)** Specify the Flourish color. */
|
|
13
|
+
fill?: Darks | Lights
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const Flourish = ({
|
|
17
|
+
children,
|
|
18
|
+
className,
|
|
19
|
+
fill = "light-yellow",
|
|
20
|
+
...props
|
|
21
|
+
}: FlourishProps): JSX.Element => {
|
|
22
|
+
const componentProps = {
|
|
23
|
+
className: clsx("coop-flourish ", className),
|
|
24
|
+
fill: `var(--color-${fill})`,
|
|
25
|
+
...props,
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<span style={{ position: "relative" }}>
|
|
30
|
+
{children}
|
|
31
|
+
<svg {...componentProps} height="10" viewBox="0 0 276 10" width="276">
|
|
32
|
+
<path d="M275.9 8.6c.1-1.6.2-1.8-.4-2.9.3-1-.3-1.2-1.8-1.1v-.3c.6-.4.2-.2 1.4-.1-.9-2.3-5.6-1.8-8.5-2.3C259 .5 246.3.7 237.4.5L185 .4l-33-.2-26.1-.2-67.4 1.2-44.3.5C10.7 2.1 1.5.4 0 3.3l1 .2L0 4v.5C8.2 7.9 26.6 7.2 35.6 7c5 0 13.5 1.6 16.5-.6C53.4 8 59.5 8 62 7.7l45 .1 42.8.3 30.7.3 44.2.6 27.8-.5 23 .8c.1-.8-.3-.5.5-.7ZM219 2.8v-.2l.8-.2h.4l.3.4H219Zm30-.1h1.2c-.8.4-.5.3-1.2 0Zm6.2.6.2-.4h.3l-.5.4Z" />
|
|
33
|
+
</svg>
|
|
34
|
+
</span>
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export default Flourish
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { InputHTMLAttributes, JSX } from "react"
|
|
2
|
+
|
|
3
|
+
import clsx from "clsx"
|
|
4
|
+
import { useId } from "react"
|
|
5
|
+
|
|
6
|
+
import { StandardSizes } from "../../../src/types"
|
|
7
|
+
|
|
8
|
+
export interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "size" | "type"> {
|
|
9
|
+
/** **(Optional)** Specify additional CSS classes to be applied to the component. */
|
|
10
|
+
className?: string
|
|
11
|
+
/** **(Optional)** Specify the Input error message. */
|
|
12
|
+
error?: { message: string; type?: string } | false | null | undefined // TODO: Extract this into a FieldError type
|
|
13
|
+
/** **(Optional)** Specify the Input hint.
|
|
14
|
+
*
|
|
15
|
+
* This text is rendered under the label to provide further guidance for users.
|
|
16
|
+
*/
|
|
17
|
+
hint?: string
|
|
18
|
+
/** **(Optional)** Specify the Input id. Will be auto-generated if not set. */
|
|
19
|
+
id?: string
|
|
20
|
+
/** **(Optional)** Specify the Input label.
|
|
21
|
+
*
|
|
22
|
+
* This property is optional in case you need to render your own label, but all form elements *must* provide a label. */
|
|
23
|
+
label?: string
|
|
24
|
+
/** Specify the Input name. */
|
|
25
|
+
name: string
|
|
26
|
+
/** **(Optional)** Specify the Input placeholder text. Do not use in place of a form label. */
|
|
27
|
+
placeholder?: string
|
|
28
|
+
/** **(Optional)** Specify the Input size. */
|
|
29
|
+
size?: StandardSizes
|
|
30
|
+
/** **(Optional)** Specify the Input type. */
|
|
31
|
+
type?: "text" | "email" | "number" | "password" | "search" | "tel" | "url"
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const Input = ({
|
|
35
|
+
"aria-placeholder": ariaPlaceholder,
|
|
36
|
+
className,
|
|
37
|
+
error = false,
|
|
38
|
+
hint,
|
|
39
|
+
id,
|
|
40
|
+
label,
|
|
41
|
+
name,
|
|
42
|
+
placeholder,
|
|
43
|
+
size = "md",
|
|
44
|
+
type = "text",
|
|
45
|
+
...props
|
|
46
|
+
}: InputProps): JSX.Element => {
|
|
47
|
+
const internalId = useId()
|
|
48
|
+
|
|
49
|
+
id = id ?? internalId
|
|
50
|
+
|
|
51
|
+
const componentProps = {
|
|
52
|
+
"aria-placeholder": placeholder ?? ariaPlaceholder ?? undefined,
|
|
53
|
+
className: clsx("coop-input", className),
|
|
54
|
+
"data-error": error ? "" : undefined,
|
|
55
|
+
"data-size": size.length && size !== "md" ? size : undefined,
|
|
56
|
+
id,
|
|
57
|
+
name,
|
|
58
|
+
placeholder,
|
|
59
|
+
type,
|
|
60
|
+
...props,
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<div className="coop-field">
|
|
65
|
+
{label && (
|
|
66
|
+
<label className="coop-form--label" htmlFor={id}>
|
|
67
|
+
{label}
|
|
68
|
+
</label>
|
|
69
|
+
)}
|
|
70
|
+
{hint && <p className="coop-form--hint">{hint}</p>}
|
|
71
|
+
{error && <span className="coop-form--error">{error.message}</span>}
|
|
72
|
+
<input {...componentProps} />
|
|
73
|
+
</div>
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export default Input
|
|
@@ -1,31 +1,34 @@
|
|
|
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"
|
|
9
10
|
import { SearchIcon } from "../Icon"
|
|
11
|
+
import Input, { InputProps } from "../Input"
|
|
10
12
|
|
|
11
|
-
export interface SearchBoxProps
|
|
13
|
+
export interface SearchBoxProps
|
|
14
|
+
extends Omit<InputHTMLAttributes<HTMLInputElement>, "size" | "type"> {
|
|
12
15
|
/** **(Optional)** Specify a server endpoint to submit the form. Will be ignored if onSubmit is also set. */
|
|
13
16
|
action?: string
|
|
14
|
-
/** **(Optional)** Specify whether or not to enable autocomplete on the input field. Default: `off`. */
|
|
15
|
-
autoComplete?: "off" | "on"
|
|
16
17
|
/** **(Optional)** Specify props to forward to the Button element. Use `label` to set Button text. */
|
|
17
18
|
button?: Pick<ButtonProps, "className" | "loadingText"> & { label?: React.ReactNode }
|
|
18
19
|
/** **(Optional)** Specify additional CSS classes to be applied to the component. */
|
|
19
20
|
className?: string
|
|
21
|
+
/** **(Optional)** Specify the Input id. Will be auto-generated if not set. */
|
|
22
|
+
id?: string
|
|
20
23
|
/** Specify the label displayed above the search field. Hidden by default, but visible to screen readers. */
|
|
21
24
|
label: string
|
|
22
25
|
/** **(Optional)** Specify whether the label should be visible to humans or screenreaders. */
|
|
23
26
|
labelVisible?: boolean
|
|
24
|
-
/** **(Optional)** Specify the name
|
|
27
|
+
/** **(Optional)** Specify the Input name, also used as the URL search parameter. Defaults to `query`. */
|
|
25
28
|
name?: string
|
|
26
29
|
/** **(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
30
|
onSubmit?: React.FormEventHandler<HTMLElement> | undefined
|
|
28
|
-
/** **(Optional)** Specify placeholder text
|
|
31
|
+
/** **(Optional)** Specify the Input placeholder text Do not use in place of a form label. */
|
|
29
32
|
placeholder?: string
|
|
30
33
|
/** **(Optional)** Specify the SearchBox size. */
|
|
31
34
|
size?: StandardSizes
|
|
@@ -53,6 +56,7 @@ export const SearchBox = ({
|
|
|
53
56
|
autoComplete = "off",
|
|
54
57
|
button = defaultButtonProps,
|
|
55
58
|
className,
|
|
59
|
+
id,
|
|
56
60
|
label,
|
|
57
61
|
labelVisible = false,
|
|
58
62
|
name = "query",
|
|
@@ -63,6 +67,9 @@ export const SearchBox = ({
|
|
|
63
67
|
...props
|
|
64
68
|
}: SearchBoxProps): JSX.Element => {
|
|
65
69
|
const [isPending, setIsPending] = useState(false)
|
|
70
|
+
const internalId = useId()
|
|
71
|
+
|
|
72
|
+
id = id ?? internalId
|
|
66
73
|
|
|
67
74
|
const handleSubmit = useCallback(
|
|
68
75
|
async (event: React.FormEvent<HTMLFormElement>) => {
|
|
@@ -81,12 +88,10 @@ export const SearchBox = ({
|
|
|
81
88
|
[onSubmit, isPending]
|
|
82
89
|
)
|
|
83
90
|
|
|
84
|
-
const id = useId()
|
|
85
|
-
|
|
86
91
|
const formProps = {
|
|
87
92
|
action: action ?? undefined,
|
|
88
93
|
className: clsx("coop-search-box", className),
|
|
89
|
-
"data-size": size
|
|
94
|
+
//"data-size": size && size !== "md" ? size : undefined,
|
|
90
95
|
"data-variant": variant.length && variant !== "green" ? variant : undefined,
|
|
91
96
|
onSubmit: onSubmit ? handleSubmit : undefined,
|
|
92
97
|
}
|
|
@@ -106,7 +111,8 @@ export const SearchBox = ({
|
|
|
106
111
|
id,
|
|
107
112
|
name,
|
|
108
113
|
placeholder,
|
|
109
|
-
|
|
114
|
+
size: size as keyof InputProps["size"],
|
|
115
|
+
type: "search" as keyof InputProps["type"],
|
|
110
116
|
...props,
|
|
111
117
|
}
|
|
112
118
|
|
|
@@ -116,7 +122,7 @@ export const SearchBox = ({
|
|
|
116
122
|
{label}
|
|
117
123
|
</label>
|
|
118
124
|
<div className="coop-search-box--inner">
|
|
119
|
-
<
|
|
125
|
+
<Input {...inputProps} />
|
|
120
126
|
<Button {...buttonProps}>{button.label}</Button>
|
|
121
127
|
</div>
|
|
122
128
|
</form>
|
package/src/index.ts
CHANGED
|
@@ -3,7 +3,9 @@ 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/Flourish"
|
|
6
7
|
export * from "./components/Image"
|
|
8
|
+
export * from "./components/Input"
|
|
7
9
|
export * from "./components/Pill"
|
|
8
10
|
export * from "./components/RootSVG"
|
|
9
11
|
export * from "./components/SearchBox"
|