@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.
@@ -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,4 @@
1
+ import Flourish from "./Flourish";
2
+ export default Flourish;
3
+ export { Flourish };
4
+ export * from "./Flourish";
@@ -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 };
@@ -0,0 +1,4 @@
1
+ import Input from "./Input";
2
+ export default Input;
3
+ export { Input };
4
+ export * from "./Input";
@@ -0,0 +1,5 @@
1
+ import { Input } from './Input.js';
2
+
3
+
4
+
5
+ export { Input, Input as default };
@@ -2,7 +2,7 @@ import { jsx } from 'react/jsx-runtime';
2
2
 
3
3
  const RootSVG = () => {
4
4
  return (jsx("svg", { height: "0", style: {
5
- clip: "rect(0,0,0,0)}",
5
+ clip: "rect(0,0,0,0)",
6
6
  clipPath: "inset(50%)",
7
7
  overflow: "hidden",
8
8
  position: "absolute",
@@ -1,32 +1,32 @@
1
- import React, { HTMLAttributes } from "react";
2
- import { type JSX } from "react";
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 HTMLAttributes<HTMLInputElement> {
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 of the input element, also used as the URL search parameter. Defaults to `query`. */
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 for the search field. Do not in place of a form label. */
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, useCallback, useId } from 'react';
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.length && size !== "md" ? size : undefined,
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("input", { ...inputProps }), jsx(Button, { ...buttonProps, children: button.label })] })] }));
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.30.2",
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.54.2",
60
- "@storybook/addon-a11y": "^9.1.1",
61
- "@storybook/addon-docs": "^9.1.1",
62
- "@storybook/addon-onboarding": "^9.1.1",
63
- "@storybook/react-vite": "^9.1.1",
64
- "@testing-library/jest-dom": "^6.6.4",
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.9",
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.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.26.1"
83
+ "@coopdigital/styles": "^0.28.0"
84
84
  },
85
- "gitHead": "0893d2c258c7fd02aa00a3340edcf1f1aec81a0a"
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,5 @@
1
+ import Flourish from "./Flourish"
2
+
3
+ export default Flourish
4
+ export { Flourish }
5
+ export * from "./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
@@ -0,0 +1,5 @@
1
+ import Input from "./Input"
2
+
3
+ export default Input
4
+ export { Input }
5
+ export * from "./Input"
@@ -3,7 +3,7 @@ export const RootSVG = () => {
3
3
  <svg
4
4
  height="0"
5
5
  style={{
6
- clip: "rect(0,0,0,0)}",
6
+ clip: "rect(0,0,0,0)",
7
7
  clipPath: "inset(50%)",
8
8
  overflow: "hidden",
9
9
  position: "absolute",
@@ -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, { HTMLAttributes, useCallback, useId, useState } from "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 extends HTMLAttributes<HTMLInputElement> {
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 of the input element, also used as the URL search parameter. Defaults to `query`. */
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 for the search field. Do not in place of a form label. */
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.length && size !== "md" ? size : undefined,
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
- type: "search",
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
- <input {...inputProps}></input>
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"