@coopdigital/react 1.2.6 → 1.3.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.
@@ -6,7 +6,7 @@ import React, { useState, useCallback } from 'react';
6
6
  import { hasUserBg } from '../../utils/index.js';
7
7
  import { LoadingIcon } from '../icons/LoadingIcon.js';
8
8
 
9
- const Button = ({ as, children, className, href, isDisabled = false, isFullWidth = false, isLoading = false, loadingText = "Loading", onClick, ref, size = "md", variant = "solid", ...props }) => {
9
+ const Button = ({ as, children, className, href, isDisabled = false, isFullWidth = false, isLoading = false, loadingText = "Loading", onClick, ref, size, variant = "solid", ...props }) => {
10
10
  const element = as !== null && as !== void 0 ? as : (href ? "a" : "button");
11
11
  const [isPending, setIsPending] = useState(false);
12
12
  const handleClick = useCallback(async (event) => {
@@ -24,7 +24,7 @@ const Button = ({ as, children, className, href, isDisabled = false, isFullWidth
24
24
  "aria-disabled": isDisabled ? true : undefined,
25
25
  className: clsx(variant == "text" ? "coop-link" : "coop-button", !hasUserBg(className) && variant === "solid" && "bg-teal", className),
26
26
  "data-loading": isLoading || isPending ? true : undefined,
27
- "data-size": size.length && size !== "md" ? size : undefined,
27
+ "data-size": size !== null && size !== void 0 ? size : undefined,
28
28
  "data-variant": variant !== "text" ? variant : undefined,
29
29
  "data-width": isFullWidth ? "full" : undefined,
30
30
  href,
@@ -2,12 +2,12 @@ import { jsx } from 'react/jsx-runtime';
2
2
  import clsx from 'clsx';
3
3
  import { useId } from '../../hooks/useId.js';
4
4
 
5
- const Checkbox = ({ className, disabled, error = false, id, name, ref, size = "md", ...props }) => {
5
+ const Checkbox = ({ className, disabled, error = false, id, name, ref, size, ...props }) => {
6
6
  const uid = useId(id);
7
7
  const componentProps = {
8
8
  className: clsx("coop-checkbox", "coop-field-element", className),
9
9
  "data-error": error || undefined,
10
- "data-size": size.length && size !== "md" ? size : undefined,
10
+ "data-size": size !== null && size !== void 0 ? size : undefined,
11
11
  disabled,
12
12
  id: uid,
13
13
  name,
@@ -40,7 +40,7 @@ const Calendar = ({ captionLayout = "label", className, disabled, endMonth, form
40
40
  ...formatters,
41
41
  }, navLayout: "around", showOutsideDays: showOutsideDays, startMonth: startMonth, weekStartsOn: 1, ...props }));
42
42
  };
43
- const DatePicker = ({ className, closeOnSelect = true, dateFormat = "dd/MM/yyyy", disabled, disabledDates, endDate, error = false, id, initialDate = now, initialSelected = false, mode = "single", name, onChange, onSelect, ref, required = false, size = "md", startDate, ...props }) => {
43
+ const DatePicker = ({ className, closeOnSelect = true, dateFormat = "dd/MM/yyyy", disabled, disabledDates, endDate, error = false, id, initialDate = now, initialSelected = false, mode = "single", name, onChange, onSelect, ref, required = false, size, startDate, ...props }) => {
44
44
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0;
45
45
  const uid = useId(id);
46
46
  initialDate = getInitialDate(mode, initialDate);
@@ -4,13 +4,13 @@ import { Error } from '../FieldMarkers/Error.js';
4
4
  import { Hint } from '../FieldMarkers/Hint.js';
5
5
  import { Legend } from '../FieldMarkers/Legend.js';
6
6
 
7
- const Fieldset = ({ children, className, disabled, error = false, hideErrorBar = false, ref, size = "md", ...props }) => {
7
+ const Fieldset = ({ children, className, disabled, error = false, hideErrorBar = false, ref, size, ...props }) => {
8
8
  const componentProps = {
9
9
  "aria-disabled": disabled,
10
10
  className: clsx("coop-fieldset", className),
11
11
  "data-error": error || undefined,
12
12
  "data-hide-error": hideErrorBar || undefined,
13
- "data-size": size.length && size !== "md" ? size : undefined,
13
+ "data-size": size !== null && size !== void 0 ? size : undefined,
14
14
  disabled,
15
15
  ...props,
16
16
  };
@@ -2,12 +2,12 @@ import { jsx } from 'react/jsx-runtime';
2
2
  import clsx from 'clsx';
3
3
  import { useId } from '../../hooks/useId.js';
4
4
 
5
- const Radio = ({ className, disabled, error = false, id, name, ref, size = "md", ...props }) => {
5
+ const Radio = ({ className, disabled, error = false, id, name, ref, size, ...props }) => {
6
6
  const uid = useId(id);
7
7
  const componentProps = {
8
8
  className: clsx("coop-radio", "coop-field-element", className),
9
9
  "data-error": error || undefined,
10
- "data-size": size.length && size !== "md" ? size : undefined,
10
+ "data-size": size !== null && size !== void 0 ? size : undefined,
11
11
  disabled,
12
12
  id: uid,
13
13
  name,
@@ -20,7 +20,7 @@ const defaultButtonText = React.createElement(SearchIcon, {
20
20
  stroke: "currentColor",
21
21
  width: 24,
22
22
  });
23
- const Searchbox = ({ action, children, className, id, label, labelVisible = false, onSubmit, ref, size = "md", variant = "solid", ...props }) => {
23
+ const Searchbox = ({ action, children, className, id, label, labelVisible = false, onSubmit, ref, size, variant = "solid", ...props }) => {
24
24
  const slots = { ...useSlots(componentSlots, children) };
25
25
  const [isPending, setIsPending] = useState(false);
26
26
  const uid = useId(id);
@@ -43,7 +43,7 @@ const Searchbox = ({ action, children, className, id, label, labelVisible = fals
43
43
  const formProps = {
44
44
  action: action !== null && action !== void 0 ? action : undefined,
45
45
  className: clsx("coop-searchbox", borderClass, className),
46
- "data-size": size && size !== "md" ? size : undefined,
46
+ "data-size": size !== null && size !== void 0 ? size : undefined,
47
47
  "data-variant": variant.length && variant !== "solid" ? variant : undefined,
48
48
  id: uid + "-form",
49
49
  onSubmit: onSubmit ? handleSubmit : undefined,
@@ -2,12 +2,12 @@ import { jsx } from 'react/jsx-runtime';
2
2
  import clsx from 'clsx';
3
3
  import { useId } from '../../hooks/useId.js';
4
4
 
5
- const Select = ({ children, className, disabled, error, id, name, ref, size = "md", ...props }) => {
5
+ const Select = ({ children, className, disabled, error, id, name, ref, size, ...props }) => {
6
6
  const uid = useId(id);
7
7
  const componentProps = {
8
8
  className: clsx("coop-select", "coop-field-element", className),
9
9
  "data-error": error !== null && error !== void 0 ? error : undefined,
10
- "data-size": size.length && size !== "md" ? size : undefined,
10
+ "data-size": size !== null && size !== void 0 ? size : undefined,
11
11
  disabled,
12
12
  id: uid,
13
13
  name,
@@ -2,14 +2,14 @@ import { jsxs, jsx } from 'react/jsx-runtime';
2
2
  import clsx from 'clsx';
3
3
  import { useId } from '../../hooks/useId.js';
4
4
 
5
- const TextInput = ({ "aria-placeholder": ariaPlaceholder, className, disabled, error = false, id, name, placeholder, prefix, prefixInline = false, ref, size = "md", suffix, suffixInline = false, type = "text", ...props }) => {
5
+ const TextInput = ({ "aria-placeholder": ariaPlaceholder, className, disabled, error = false, id, name, placeholder, prefix, prefixInline = false, ref, size, suffix, suffixInline = false, type = "text", ...props }) => {
6
6
  var _a;
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
10
  className: clsx("coop-text-input", "coop-field-element", className),
11
11
  "data-error": error || undefined,
12
- "data-size": size.length && size !== "md" ? size : undefined,
12
+ "data-size": (size === null || size === void 0 ? void 0 : size.length) ? size : undefined,
13
13
  disabled,
14
14
  id: uid,
15
15
  name,
@@ -10,7 +10,7 @@ const DEBOUNCE_DELAY = 750;
10
10
  const charCountMessage = (remaining) => {
11
11
  return `You have ${Math.abs(remaining).toLocaleString()} ${Math.abs(remaining) === 1 ? "character" : "characters"} ${remaining < 0 ? "too many" : "remaining"}`;
12
12
  };
13
- const Textarea = ({ "aria-placeholder": ariaPlaceholder, className, cols = 30, counter = false, cutoff = false, disabled = false, error = false, id, maxLength, name, onChange: userOnChange = undefined, placeholder, ref, rows = 4, size = "md", ...props }) => {
13
+ const Textarea = ({ "aria-placeholder": ariaPlaceholder, className, cols = 30, counter = false, cutoff = false, disabled = false, error = false, id, maxLength, name, onChange: userOnChange = undefined, placeholder, ref, rows = 4, size, ...props }) => {
14
14
  var _a;
15
15
  const uid = useId(id);
16
16
  const componentProps = {
@@ -18,7 +18,7 @@ const Textarea = ({ "aria-placeholder": ariaPlaceholder, className, cols = 30, c
18
18
  className: clsx("coop-textarea", "coop-field-element", className),
19
19
  cols,
20
20
  "data-error": error !== null && error !== void 0 ? error : undefined,
21
- "data-size": size.length && size !== "md" ? size : undefined,
21
+ "data-size": size !== null && size !== void 0 ? size : undefined,
22
22
  disabled,
23
23
  id: uid,
24
24
  maxLength: cutoff ? maxLength : undefined,
@@ -1,12 +1,20 @@
1
1
  import type { HTMLAttributes, JSX, ReactNode, Ref } from "react";
2
2
  import React from "react";
3
3
  export interface ValidationSummaryProps extends HTMLAttributes<HTMLDivElement> {
4
- /** **(Optional)** Specify if the summary should be focused and the parent form scrolled into view if there are errors. */
4
+ /** **(Optional)** Specify if the summary should be focused and the parent form scrolled into view if there are errors.
5
+ *
6
+ * Default: true
7
+ */
5
8
  autoScroll?: boolean;
6
9
  /** **(Optional)** This should be a set of `ValidationSummary.Heading`, `ValidationSummary.Prompt` and `ValidationSummary.Errors` components. */
7
10
  children?: ReactNode;
8
11
  /** **(Optional)** Specify additional CSS classes to be applied to the component. */
9
12
  className?: string;
13
+ /** **(Optional)** Specify if the summary should always render regardless of error state. Use this if you want to control the logic in your own code.
14
+ *
15
+ * Default: false
16
+ */
17
+ forceMount?: boolean;
10
18
  /** **(Optional)** Specify a custom React ref for this component. */
11
19
  ref?: Ref<HTMLDivElement>;
12
20
  }
@@ -41,7 +49,7 @@ interface ValidationSummaryErrorsProps extends HTMLAttributes<HTMLDivElement> {
41
49
  errors?: Record<string, FieldError>;
42
50
  }
43
51
  export declare const ValidationSummary: {
44
- ({ autoScroll, children, className, ref, ...props }: ValidationSummaryProps): JSX.Element | null;
52
+ ({ autoScroll, children, className, forceMount, ref, ...props }: ValidationSummaryProps): JSX.Element | null;
45
53
  Heading: {
46
54
  ({ as, children, className, }: ValidationSummaryHeadingProps): JSX.Element;
47
55
  config: {
@@ -12,7 +12,7 @@ const componentSlots = {
12
12
  ValidationSummaryHeading: null,
13
13
  ValidationSummaryPrompt: null,
14
14
  };
15
- const ValidationSummary = ({ autoScroll = true, children, className, ref, ...props }) => {
15
+ const ValidationSummary = ({ autoScroll = true, children, className, forceMount = false, ref, ...props }) => {
16
16
  var _a;
17
17
  const slots = { ...useSlots(componentSlots, children) };
18
18
  const errors = React.isValidElement(slots.ValidationSummaryErrors) &&
@@ -28,7 +28,7 @@ const ValidationSummary = ({ autoScroll = true, children, className, ref, ...pro
28
28
  (_b = internalRef.current) === null || _b === void 0 ? void 0 : _b.focus();
29
29
  }
30
30
  }, [autoScroll, errors, hasErrors]);
31
- if (!hasErrors) {
31
+ if (!hasErrors && !forceMount) {
32
32
  return null;
33
33
  }
34
34
  const componentProps = {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@coopdigital/react",
3
3
  "type": "module",
4
- "version": "1.2.6",
4
+ "version": "1.3.0",
5
5
  "private": false,
6
6
  "publishConfig": {
7
7
  "access": "public"
@@ -67,7 +67,7 @@
67
67
  "@storybook/react-vite": "^10.4.0",
68
68
  "@testing-library/jest-dom": "^6.9.1",
69
69
  "@testing-library/react": "^16.3.2",
70
- "@types/react": "^19.2.14",
70
+ "@types/react": "^19.2.15",
71
71
  "@types/react-dom": "^19.2.3",
72
72
  "react": "^19.2.6",
73
73
  "react-dom": "^19.2.6",
@@ -84,11 +84,11 @@
84
84
  "storybook": "$storybook"
85
85
  },
86
86
  "dependencies": {
87
- "@coopdigital/styles": "^1.2.1",
87
+ "@coopdigital/styles": "^1.3.0",
88
88
  "@radix-ui/react-popover": "^1.1.15",
89
89
  "clsx": "^2.1.1",
90
90
  "merge-refs": "^2.0.0",
91
91
  "react-day-picker": "^10.0.0"
92
92
  },
93
- "gitHead": "9be9996ac210f4c20f42dc23404930e62fea11b1"
93
+ "gitHead": "12de6a2c1f7249320ee5924bed3eddf7c6e9257e"
94
94
  }
@@ -51,7 +51,7 @@ export const Button = ({
51
51
  loadingText = "Loading",
52
52
  onClick,
53
53
  ref,
54
- size = "md",
54
+ size,
55
55
  variant = "solid",
56
56
  ...props
57
57
  }: ButtonProps): JSX.Element => {
@@ -82,7 +82,7 @@ export const Button = ({
82
82
  className
83
83
  ),
84
84
  "data-loading": isLoading || isPending ? true : undefined,
85
- "data-size": size.length && size !== "md" ? size : undefined,
85
+ "data-size": size ?? undefined,
86
86
  "data-variant": variant !== "text" ? variant : undefined,
87
87
  "data-width": isFullWidth ? "full" : undefined,
88
88
  href,
@@ -32,14 +32,14 @@ export const Checkbox = ({
32
32
  id,
33
33
  name,
34
34
  ref,
35
- size = "md",
35
+ size,
36
36
  ...props
37
37
  }: CheckboxProps): JSX.Element => {
38
38
  const uid = useId(id)
39
39
  const componentProps = {
40
40
  className: clsx("coop-checkbox", "coop-field-element", className),
41
41
  "data-error": error || undefined,
42
- "data-size": size.length && size !== "md" ? size : undefined,
42
+ "data-size": size ?? undefined,
43
43
  disabled,
44
44
  id: uid,
45
45
  name,
@@ -179,7 +179,7 @@ export const DatePicker = ({
179
179
  onSelect,
180
180
  ref,
181
181
  required = false,
182
- size = "md",
182
+ size,
183
183
  startDate,
184
184
  ...props
185
185
  }: DatePickerProps): JSX.Element => {
@@ -31,7 +31,7 @@ export const Fieldset = ({
31
31
  error = false,
32
32
  hideErrorBar = false,
33
33
  ref,
34
- size = "md",
34
+ size,
35
35
  ...props
36
36
  }: FieldsetProps): JSX.Element => {
37
37
  const componentProps = {
@@ -39,7 +39,7 @@ export const Fieldset = ({
39
39
  className: clsx("coop-fieldset", className),
40
40
  "data-error": error || undefined,
41
41
  "data-hide-error": hideErrorBar || undefined,
42
- "data-size": size.length && size !== "md" ? size : undefined,
42
+ "data-size": size ?? undefined,
43
43
  disabled,
44
44
  ...props,
45
45
  }
@@ -28,7 +28,7 @@ export const Radio = ({
28
28
  id,
29
29
  name,
30
30
  ref,
31
- size = "md",
31
+ size,
32
32
  ...props
33
33
  }: RadioProps): JSX.Element => {
34
34
  const uid = useId(id)
@@ -36,7 +36,7 @@ export const Radio = ({
36
36
  const componentProps = {
37
37
  className: clsx("coop-radio", "coop-field-element", className),
38
38
  "data-error": error || undefined,
39
- "data-size": size.length && size !== "md" ? size : undefined,
39
+ "data-size": size ?? undefined,
40
40
  disabled,
41
41
  id: uid,
42
42
  name,
@@ -61,7 +61,7 @@ export const Searchbox = ({
61
61
  labelVisible = false,
62
62
  onSubmit,
63
63
  ref,
64
- size = "md",
64
+ size,
65
65
  variant = "solid",
66
66
  ...props
67
67
  }: SearchboxProps): JSX.Element => {
@@ -95,7 +95,7 @@ export const Searchbox = ({
95
95
  const formProps = {
96
96
  action: action ?? undefined,
97
97
  className: clsx("coop-searchbox", borderClass, className),
98
- "data-size": size && size !== "md" ? size : undefined,
98
+ "data-size": size ?? undefined,
99
99
  "data-variant": variant.length && variant !== "solid" ? variant : undefined,
100
100
  id: uid + "-form",
101
101
  onSubmit: onSubmit ? handleSubmit : undefined,
@@ -55,14 +55,14 @@ export const Select = ({
55
55
  id,
56
56
  name,
57
57
  ref,
58
- size = "md",
58
+ size,
59
59
  ...props
60
60
  }: SelectProps): JSX.Element => {
61
61
  const uid = useId(id)
62
62
  const componentProps = {
63
63
  className: clsx("coop-select", "coop-field-element", className),
64
64
  "data-error": error ?? undefined,
65
- "data-size": size.length && size !== "md" ? size : undefined,
65
+ "data-size": size ?? undefined,
66
66
  disabled,
67
67
  id: uid,
68
68
  name,
@@ -60,7 +60,7 @@ export const TextInput = ({
60
60
  prefix,
61
61
  prefixInline = false,
62
62
  ref,
63
- size = "md",
63
+ size,
64
64
  suffix,
65
65
  suffixInline = false,
66
66
  type = "text",
@@ -72,7 +72,7 @@ export const TextInput = ({
72
72
  "aria-placeholder": placeholder ?? ariaPlaceholder ?? undefined,
73
73
  className: clsx("coop-text-input", "coop-field-element", className),
74
74
  "data-error": error || undefined,
75
- "data-size": size.length && size !== "md" ? size : undefined,
75
+ "data-size": size?.length ? size : undefined,
76
76
  disabled,
77
77
  id: uid,
78
78
  name,
@@ -62,7 +62,7 @@ export const Textarea = ({
62
62
  placeholder,
63
63
  ref,
64
64
  rows = 4,
65
- size = "md",
65
+ size,
66
66
  ...props
67
67
  }: TextareaProps): JSX.Element => {
68
68
  const uid = useId(id)
@@ -72,7 +72,7 @@ export const Textarea = ({
72
72
  className: clsx("coop-textarea", "coop-field-element", className),
73
73
  cols,
74
74
  "data-error": error ?? undefined,
75
- "data-size": size.length && size !== "md" ? size : undefined,
75
+ "data-size": size ?? undefined,
76
76
  disabled,
77
77
  id: uid,
78
78
  maxLength: cutoff ? maxLength : undefined,
@@ -11,12 +11,20 @@ import { useSlots } from "../../hooks/useSlots"
11
11
  import { getFieldElement, sanitizeFieldId } from "./validationsummary-utils"
12
12
 
13
13
  export interface ValidationSummaryProps extends HTMLAttributes<HTMLDivElement> {
14
- /** **(Optional)** Specify if the summary should be focused and the parent form scrolled into view if there are errors. */
14
+ /** **(Optional)** Specify if the summary should be focused and the parent form scrolled into view if there are errors.
15
+ *
16
+ * Default: true
17
+ */
15
18
  autoScroll?: boolean
16
19
  /** **(Optional)** This should be a set of `ValidationSummary.Heading`, `ValidationSummary.Prompt` and `ValidationSummary.Errors` components. */
17
20
  children?: ReactNode
18
21
  /** **(Optional)** Specify additional CSS classes to be applied to the component. */
19
22
  className?: string
23
+ /** **(Optional)** Specify if the summary should always render regardless of error state. Use this if you want to control the logic in your own code.
24
+ *
25
+ * Default: false
26
+ */
27
+ forceMount?: boolean
20
28
  /** **(Optional)** Specify a custom React ref for this component. */
21
29
  ref?: Ref<HTMLDivElement>
22
30
  }
@@ -66,6 +74,7 @@ export const ValidationSummary = ({
66
74
  autoScroll = true,
67
75
  children,
68
76
  className,
77
+ forceMount = false,
69
78
  ref,
70
79
  ...props
71
80
  }: ValidationSummaryProps): JSX.Element | null => {
@@ -87,7 +96,7 @@ export const ValidationSummary = ({
87
96
  }
88
97
  }, [autoScroll, errors, hasErrors])
89
98
 
90
- if (!hasErrors) {
99
+ if (!hasErrors && !forceMount) {
91
100
  return null
92
101
  }
93
102