@coopdigital/react 0.47.0 → 0.48.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.
@@ -4,12 +4,22 @@ export interface AlertBannerProps extends HTMLAttributes<HTMLDivElement> {
4
4
  children?: string | ReactNode;
5
5
  /** **(Optional)** Specify additional CSS classes to be applied to the component. */
6
6
  className?: string;
7
- /** Specify the main title of the banner, rendered as a `h2`. */
8
- heading: string;
9
7
  /** **(Optional)** Specify a custom React ref for this component. */
10
8
  ref?: Ref<HTMLDivElement>;
11
9
  /** **(Optional)** Specify the AlertBanner variant. */
12
10
  variant?: "black" | "default";
13
11
  }
14
- export declare const AlertBanner: ({ children, className, heading, ref, variant, ...props }: AlertBannerProps) => JSX.Element;
12
+ interface AlertBannerHeadingProps extends HTMLAttributes<HTMLHeadingElement> {
13
+ /** **(Optional)** Content inside the Heading. */
14
+ children?: React.ReactNode;
15
+ /** **(Optional)** Specify additional CSS classes to be applied to the Heading. */
16
+ className?: string;
17
+ }
18
+ export declare const AlertBanner: {
19
+ ({ children, className, ref, variant, ...props }: AlertBannerProps): JSX.Element;
20
+ Heading: {
21
+ ({ children, className }: AlertBannerHeadingProps): JSX.Element;
22
+ displayName: string;
23
+ };
24
+ };
15
25
  export default AlertBanner;
@@ -1,13 +1,18 @@
1
- import { jsx, jsxs } from 'react/jsx-runtime';
1
+ import { jsx } from 'react/jsx-runtime';
2
2
  import clsx from 'clsx';
3
3
 
4
- const AlertBanner = ({ children, className, heading, ref, variant = "default", ...props }) => {
4
+ const AlertBanner = ({ children, className, ref, variant = "default", ...props }) => {
5
5
  const componentProps = {
6
6
  className: clsx("coop-alert-banner", className),
7
7
  "data-variant": variant,
8
8
  ...props,
9
9
  };
10
- return (jsx("aside", { ...componentProps, ref: ref, children: jsxs("div", { className: "coop-alert-banner--inner", children: [jsx("h2", { id: "coop-alert-banner--headline", children: heading }), children] }) }));
10
+ return (jsx("aside", { ...componentProps, ref: ref, children: children }));
11
11
  };
12
+ const AlertBannerHeading = ({ children, className }) => {
13
+ return jsx("h2", { className: className, children: children });
14
+ };
15
+ AlertBannerHeading.displayName = "AlertBanner.Heading";
16
+ AlertBanner.Heading = AlertBannerHeading;
12
17
 
13
18
  export { AlertBanner, AlertBanner as default };
@@ -5,7 +5,7 @@ import { useId } from '../../hooks/useId.js';
5
5
  const Checkbox = ({ className, disabled, error = false, id, name, ref, size = "md", ...props }) => {
6
6
  const uid = useId(id);
7
7
  const componentProps = {
8
- className: clsx("coop-checkbox", className),
8
+ className: clsx("coop-checkbox", "coop-field-element", className),
9
9
  "data-error": error || undefined,
10
10
  "data-size": size.length && size !== "md" ? size : undefined,
11
11
  disabled,
@@ -15,6 +15,7 @@ const componentSlots = {
15
15
  FieldHint: null,
16
16
  FieldLabel: null,
17
17
  Radio: null,
18
+ Select: null,
18
19
  Textarea: null,
19
20
  TextInput: null,
20
21
  };
@@ -5,7 +5,7 @@ import { useId } from '../../hooks/useId.js';
5
5
  const Radio = ({ className, disabled, error = false, id, name, ref, size = "md", ...props }) => {
6
6
  const uid = useId(id);
7
7
  const componentProps = {
8
- className: clsx("coop-radio", className),
8
+ className: clsx("coop-radio", "coop-field-element", className),
9
9
  "data-error": error || undefined,
10
10
  "data-size": size.length && size !== "md" ? size : undefined,
11
11
  disabled,
@@ -0,0 +1,46 @@
1
+ import type { JSX, OptgroupHTMLAttributes, OptionHTMLAttributes, ReactNode, Ref, SelectHTMLAttributes } from "react";
2
+ import { StandardSizes } from "../../../src/types";
3
+ export interface SelectProps extends Omit<SelectHTMLAttributes<HTMLSelectElement>, "size"> {
4
+ /** **(Optional)** Options inside the Select. This should be a set of `Select.Option` or `Select.OptionGroup` components. */
5
+ children?: ReactNode;
6
+ /** **(Optional)** Specify additional CSS classes to be applied to the component. */
7
+ className?: string;
8
+ /** **(Optional)** Specify whether the Select should be disabled. Refer to Experience Library guidance on disabled form controls and accessibility. */
9
+ disabled?: boolean;
10
+ /** **(Optional)** Specify the Select error state. */
11
+ error?: boolean;
12
+ /** **(Optional)** Specify the Select id. Will be auto-generated if not set. */
13
+ id?: string;
14
+ /** Specify the Select name. */
15
+ name: string;
16
+ /** **(Optional)** Specify a custom React ref for this component. */
17
+ ref?: Ref<HTMLSelectElement>;
18
+ /** **(Optional)** Specify the Select size. */
19
+ size?: StandardSizes;
20
+ }
21
+ interface SelectOptionGroupProps extends OptgroupHTMLAttributes<HTMLOptGroupElement> {
22
+ /** **(Optional)** Main content inside the Select option. It can be any valid JSX or string. */
23
+ children?: ReactNode;
24
+ /** Specify the Select option group label. */
25
+ label: string;
26
+ }
27
+ interface SelectOptionProps extends OptionHTMLAttributes<HTMLOptionElement> {
28
+ /** **(Optional)** Main content inside the Select option. It can be any valid JSX or string. */
29
+ children?: ReactNode;
30
+ /** **(Optional)** Specify additional CSS classes to be applied to the Select option. */
31
+ className?: string;
32
+ /** Value of Select option. */
33
+ value: string;
34
+ }
35
+ export declare const Select: {
36
+ ({ children, className, disabled, error, id, name, ref, size, ...props }: SelectProps): JSX.Element;
37
+ OptionGroup: {
38
+ ({ children, ...props }: SelectOptionGroupProps): JSX.Element;
39
+ displayName: string;
40
+ };
41
+ Option: {
42
+ ({ children, className, ...props }: SelectOptionProps): JSX.Element;
43
+ displayName: string;
44
+ };
45
+ };
46
+ export default Select;
@@ -0,0 +1,29 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import clsx from 'clsx';
3
+ import { useId } from '../../hooks/useId.js';
4
+
5
+ const Select = ({ children, className, disabled, error, id, name, ref, size = "md", ...props }) => {
6
+ const uid = useId(id);
7
+ const componentProps = {
8
+ className: clsx("coop-select", "coop-field-element", className),
9
+ "data-error": error !== null && error !== void 0 ? error : undefined,
10
+ "data-size": size.length && size !== "md" ? size : undefined,
11
+ disabled,
12
+ id: uid,
13
+ name,
14
+ ...props,
15
+ };
16
+ return (jsx("select", { ...componentProps, ref: ref, children: children }));
17
+ };
18
+ const SelectOptionGroup = ({ children, ...props }) => {
19
+ return jsx("optgroup", { ...props, children: children });
20
+ };
21
+ const SelectOption = ({ children, className, ...props }) => {
22
+ return (jsx("option", { className: clsx("coop-select--option", className), ...props, children: children }));
23
+ };
24
+ SelectOptionGroup.displayName = "Select.OptionGroup";
25
+ SelectOption.displayName = "Select.Option";
26
+ Select.OptionGroup = SelectOptionGroup;
27
+ Select.Option = SelectOption;
28
+
29
+ export { Select, Select as default };
@@ -0,0 +1,4 @@
1
+ import Select from "./Select";
2
+ export default Select;
3
+ export { Select };
4
+ export * from "./Select";
@@ -7,7 +7,7 @@ const TextInput = ({ "aria-placeholder": ariaPlaceholder, className, disabled, e
7
7
  const uid = useId(id);
8
8
  const componentProps = {
9
9
  "aria-placeholder": (_a = placeholder !== null && placeholder !== void 0 ? placeholder : ariaPlaceholder) !== null && _a !== void 0 ? _a : undefined,
10
- className: clsx("coop-text-input", className),
10
+ className: clsx("coop-text-input", "coop-field-element", className),
11
11
  "data-error": error || undefined,
12
12
  "data-size": size.length && size !== "md" ? size : undefined,
13
13
  disabled,
@@ -13,7 +13,7 @@ const Textarea = ({ "aria-placeholder": ariaPlaceholder, className, cols = 30, c
13
13
  const uid = useId(id);
14
14
  const componentProps = {
15
15
  "aria-placeholder": (_a = placeholder !== null && placeholder !== void 0 ? placeholder : ariaPlaceholder) !== null && _a !== void 0 ? _a : undefined,
16
- className: clsx("coop-textarea", className),
16
+ className: clsx("coop-textarea", "coop-field-element", className),
17
17
  cols,
18
18
  "data-error": error !== null && error !== void 0 ? error : undefined,
19
19
  "data-size": size.length && size !== "md" ? size : undefined,
package/dist/index.d.ts CHANGED
@@ -12,6 +12,7 @@ export * from "./components/Pill";
12
12
  export * from "./components/Radio";
13
13
  export * from "./components/RootSVG";
14
14
  export * from "./components/Searchbox";
15
+ export * from "./components/Select";
15
16
  export * from "./components/Signpost";
16
17
  export * from "./components/SkipNav";
17
18
  export * from "./components/Squircle";
package/dist/index.js CHANGED
@@ -12,6 +12,7 @@ export { Pill } from './components/Pill/Pill.js';
12
12
  export { Radio } from './components/Radio/Radio.js';
13
13
  export { RootSVG } from './components/RootSVG/RootSVG.js';
14
14
  export { Searchbox } from './components/Searchbox/Searchbox.js';
15
+ export { Select } from './components/Select/Select.js';
15
16
  export { Signpost } from './components/Signpost/Signpost.js';
16
17
  export { SkipNav } from './components/SkipNav/SkipNav.js';
17
18
  export { Squircle } from './components/Squircle/Squircle.js';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@coopdigital/react",
3
3
  "type": "module",
4
- "version": "0.47.0",
4
+ "version": "0.48.0",
5
5
  "private": false,
6
6
  "publishConfig": {
7
7
  "access": "public"
@@ -56,19 +56,19 @@
56
56
  "description": "",
57
57
  "devDependencies": {
58
58
  "@axe-core/playwright": "^4.11.0",
59
- "@playwright/test": "^1.56.1",
60
- "@storybook/addon-a11y": "^10.0.7",
61
- "@storybook/addon-docs": "^10.0.7",
62
- "@storybook/addon-onboarding": "^10.0.7",
63
- "@storybook/react-vite": "^10.0.7",
59
+ "@playwright/test": "^1.57.0",
60
+ "@storybook/addon-a11y": "^10.1.0",
61
+ "@storybook/addon-docs": "^10.1.0",
62
+ "@storybook/addon-onboarding": "^10.1.0",
63
+ "@storybook/react-vite": "^10.1.0",
64
64
  "@testing-library/jest-dom": "^6.9.1",
65
65
  "@testing-library/react": "^16.3.0",
66
- "@types/react": "^19.2.4",
66
+ "@types/react": "^19.2.7",
67
67
  "@types/react-dom": "^19.2.3",
68
68
  "react": "^19.2.0",
69
69
  "react-dom": "^19.2.0",
70
70
  "serve": "^14.2.5",
71
- "storybook": "^10.0.7"
71
+ "storybook": "^10.1.0"
72
72
  },
73
73
  "peerDependencies": {
74
74
  "react": "^19.1.0",
@@ -78,8 +78,8 @@
78
78
  "storybook": "$storybook"
79
79
  },
80
80
  "dependencies": {
81
- "@coopdigital/styles": "^0.40.0",
81
+ "@coopdigital/styles": "^0.41.0",
82
82
  "clsx": "^2.1.1"
83
83
  },
84
- "gitHead": "f28e578e8a74f005d372677975f19a707ea643ca"
84
+ "gitHead": "96d3459231c76b94984900894ac0ae2bac2f091b"
85
85
  }
@@ -7,18 +7,22 @@ export interface AlertBannerProps extends HTMLAttributes<HTMLDivElement> {
7
7
  children?: string | ReactNode
8
8
  /** **(Optional)** Specify additional CSS classes to be applied to the component. */
9
9
  className?: string
10
- /** Specify the main title of the banner, rendered as a `h2`. */
11
- heading: string
12
10
  /** **(Optional)** Specify a custom React ref for this component. */
13
11
  ref?: Ref<HTMLDivElement>
14
12
  /** **(Optional)** Specify the AlertBanner variant. */
15
13
  variant?: "black" | "default"
16
14
  }
17
15
 
16
+ interface AlertBannerHeadingProps extends HTMLAttributes<HTMLHeadingElement> {
17
+ /** **(Optional)** Content inside the Heading. */
18
+ children?: React.ReactNode
19
+ /** **(Optional)** Specify additional CSS classes to be applied to the Heading. */
20
+ className?: string
21
+ }
22
+
18
23
  export const AlertBanner = ({
19
24
  children,
20
25
  className,
21
- heading,
22
26
  ref,
23
27
  variant = "default",
24
28
  ...props
@@ -31,12 +35,17 @@ export const AlertBanner = ({
31
35
 
32
36
  return (
33
37
  <aside {...componentProps} ref={ref}>
34
- <div className="coop-alert-banner--inner">
35
- <h2 id="coop-alert-banner--headline">{heading}</h2>
36
- {children}
37
- </div>
38
+ {children}
38
39
  </aside>
39
40
  )
40
41
  }
41
42
 
43
+ const AlertBannerHeading = ({ children, className }: AlertBannerHeadingProps): JSX.Element => {
44
+ return <h2 className={className}>{children}</h2>
45
+ }
46
+
47
+ AlertBannerHeading.displayName = "AlertBanner.Heading"
48
+
49
+ AlertBanner.Heading = AlertBannerHeading
50
+
42
51
  export default AlertBanner
@@ -5,8 +5,10 @@ import clsx from "clsx"
5
5
  import { StandardSizes } from "../../../src/types"
6
6
  import { useId } from "../../hooks/useId"
7
7
 
8
- export interface CheckboxProps
9
- extends Omit<InputHTMLAttributes<HTMLInputElement>, "size" | "type"> {
8
+ export interface CheckboxProps extends Omit<
9
+ InputHTMLAttributes<HTMLInputElement>,
10
+ "size" | "type"
11
+ > {
10
12
  /** **(Optional)** Specify additional CSS classes to be applied to the component. */
11
13
  className?: string
12
14
  /** **(Optional)** Specify whether the Checkbox should be disabled. Refer to Experience Library guidance on disabled form controls and accessibility. */
@@ -35,7 +37,7 @@ export const Checkbox = ({
35
37
  }: CheckboxProps): JSX.Element => {
36
38
  const uid = useId(id)
37
39
  const componentProps = {
38
- className: clsx("coop-checkbox", className),
40
+ className: clsx("coop-checkbox", "coop-field-element", className),
39
41
  "data-error": error || undefined,
40
42
  "data-size": size.length && size !== "md" ? size : undefined,
41
43
  disabled,
@@ -17,6 +17,7 @@ const componentSlots = {
17
17
  FieldHint: null,
18
18
  FieldLabel: null,
19
19
  Radio: null,
20
+ Select: null,
20
21
  Textarea: null,
21
22
  TextInput: null,
22
23
  }
@@ -34,7 +34,7 @@ export const Radio = ({
34
34
  const uid = useId(id)
35
35
 
36
36
  const componentProps = {
37
- className: clsx("coop-radio", className),
37
+ className: clsx("coop-radio", "coop-field-element", className),
38
38
  "data-error": error || undefined,
39
39
  "data-size": size.length && size !== "md" ? size : undefined,
40
40
  disabled,
@@ -12,8 +12,10 @@ import { Label as FieldLabel } from "../FieldMarkers/Label"
12
12
  import { SearchIcon } from "../Icon"
13
13
  import TextInput, { TextInputProps } from "../TextInput"
14
14
 
15
- export interface SearchboxProps
16
- extends Omit<InputHTMLAttributes<HTMLInputElement>, "size" | "type"> {
15
+ export interface SearchboxProps extends Omit<
16
+ InputHTMLAttributes<HTMLInputElement>,
17
+ "size" | "type"
18
+ > {
17
19
  /** **(Optional)** Specify a server endpoint to submit the form. Will be ignored if onSubmit is also set. */
18
20
  action?: string
19
21
  /** **(Optional)** Specify props to forward to the Button element. Use `label` to set Button text. */
@@ -0,0 +1,97 @@
1
+ import type {
2
+ JSX,
3
+ OptgroupHTMLAttributes,
4
+ OptionHTMLAttributes,
5
+ ReactNode,
6
+ Ref,
7
+ SelectHTMLAttributes,
8
+ } from "react"
9
+
10
+ import clsx from "clsx"
11
+
12
+ import { StandardSizes } from "../../../src/types"
13
+ import { useId } from "../../hooks/useId"
14
+
15
+ export interface SelectProps extends Omit<SelectHTMLAttributes<HTMLSelectElement>, "size"> {
16
+ /** **(Optional)** Options inside the Select. This should be a set of `Select.Option` or `Select.OptionGroup` components. */
17
+ children?: ReactNode
18
+ /** **(Optional)** Specify additional CSS classes to be applied to the component. */
19
+ className?: string
20
+ /** **(Optional)** Specify whether the Select should be disabled. Refer to Experience Library guidance on disabled form controls and accessibility. */
21
+ disabled?: boolean
22
+ /** **(Optional)** Specify the Select error state. */
23
+ error?: boolean
24
+ /** **(Optional)** Specify the Select id. Will be auto-generated if not set. */
25
+ id?: string
26
+ /** Specify the Select name. */
27
+ name: string
28
+ /** **(Optional)** Specify a custom React ref for this component. */
29
+ ref?: Ref<HTMLSelectElement>
30
+ /** **(Optional)** Specify the Select size. */
31
+ size?: StandardSizes
32
+ }
33
+
34
+ interface SelectOptionGroupProps extends OptgroupHTMLAttributes<HTMLOptGroupElement> {
35
+ /** **(Optional)** Main content inside the Select option. It can be any valid JSX or string. */
36
+ children?: ReactNode
37
+ /** Specify the Select option group label. */
38
+ label: string
39
+ }
40
+
41
+ interface SelectOptionProps extends OptionHTMLAttributes<HTMLOptionElement> {
42
+ /** **(Optional)** Main content inside the Select option. It can be any valid JSX or string. */
43
+ children?: ReactNode
44
+ /** **(Optional)** Specify additional CSS classes to be applied to the Select option. */
45
+ className?: string
46
+ /** Value of Select option. */
47
+ value: string
48
+ }
49
+
50
+ export const Select = ({
51
+ children,
52
+ className,
53
+ disabled,
54
+ error,
55
+ id,
56
+ name,
57
+ ref,
58
+ size = "md",
59
+ ...props
60
+ }: SelectProps): JSX.Element => {
61
+ const uid = useId(id)
62
+ const componentProps = {
63
+ className: clsx("coop-select", "coop-field-element", className),
64
+ "data-error": error ?? undefined,
65
+ "data-size": size.length && size !== "md" ? size : undefined,
66
+ disabled,
67
+ id: uid,
68
+ name,
69
+ ...props,
70
+ }
71
+
72
+ return (
73
+ <select {...componentProps} ref={ref}>
74
+ {children}
75
+ </select>
76
+ )
77
+ }
78
+
79
+ const SelectOptionGroup = ({ children, ...props }: SelectOptionGroupProps): JSX.Element => {
80
+ return <optgroup {...props}>{children}</optgroup>
81
+ }
82
+
83
+ const SelectOption = ({ children, className, ...props }: SelectOptionProps): JSX.Element => {
84
+ return (
85
+ <option className={clsx("coop-select--option", className)} {...props}>
86
+ {children}
87
+ </option>
88
+ )
89
+ }
90
+
91
+ SelectOptionGroup.displayName = "Select.OptionGroup"
92
+ SelectOption.displayName = "Select.Option"
93
+
94
+ Select.OptionGroup = SelectOptionGroup
95
+ Select.Option = SelectOption
96
+
97
+ export default Select
@@ -0,0 +1,5 @@
1
+ import Select from "./Select"
2
+
3
+ export default Select
4
+ export { Select }
5
+ export * from "./Select"
@@ -5,8 +5,10 @@ import clsx from "clsx"
5
5
  import { StandardSizes } from "../../../src/types"
6
6
  import { useId } from "../../hooks/useId"
7
7
 
8
- export interface TextInputProps
9
- extends Omit<InputHTMLAttributes<HTMLInputElement>, "prefix" | "size" | "type"> {
8
+ export interface TextInputProps extends Omit<
9
+ InputHTMLAttributes<HTMLInputElement>,
10
+ "prefix" | "size" | "type"
11
+ > {
10
12
  /** **(Optional)** Specify additional CSS classes to be applied to the component. */
11
13
  className?: string
12
14
  /** **(Optional)** Specify whether the TextInput should be disabled. Refer to Experience Library guidance on disabled form controls and accessibility. */
@@ -62,7 +64,7 @@ export const TextInput = ({
62
64
 
63
65
  const componentProps = {
64
66
  "aria-placeholder": placeholder ?? ariaPlaceholder ?? undefined,
65
- className: clsx("coop-text-input", className),
67
+ className: clsx("coop-text-input", "coop-field-element", className),
66
68
  "data-error": error || undefined,
67
69
  "data-size": size.length && size !== "md" ? size : undefined,
68
70
  disabled,
@@ -69,7 +69,7 @@ export const Textarea = ({
69
69
 
70
70
  const componentProps = {
71
71
  "aria-placeholder": placeholder ?? ariaPlaceholder ?? undefined,
72
- className: clsx("coop-textarea", className),
72
+ className: clsx("coop-textarea", "coop-field-element", className),
73
73
  cols,
74
74
  "data-error": error ?? undefined,
75
75
  "data-size": size.length && size !== "md" ? size : undefined,
package/src/index.ts CHANGED
@@ -12,6 +12,7 @@ export * from "./components/Pill"
12
12
  export * from "./components/Radio"
13
13
  export * from "./components/RootSVG"
14
14
  export * from "./components/Searchbox"
15
+ export * from "./components/Select"
15
16
  export * from "./components/Signpost"
16
17
  export * from "./components/SkipNav"
17
18
  export * from "./components/Squircle"