@coopdigital/react 1.27.2 → 1.29.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/Button/Button.js +1 -1
- package/dist/components/Card/Card.js +1 -1
- package/dist/components/Checkbox/Checkbox.d.ts +3 -3
- package/dist/components/Checkbox/Checkbox.js +5 -3
- package/dist/components/Combobox/Combobox.js +6 -3
- package/dist/components/DatePicker/DatePicker.js +5 -3
- package/dist/components/Dialog/Dialog.js +1 -1
- package/dist/components/Expandable/Expandable.js +1 -1
- package/dist/components/Field/Field.context.js +5 -6
- package/dist/components/Field/Field.d.ts +2 -2
- package/dist/components/Field/Field.js +40 -20
- package/dist/components/FieldMarkers/Error.js +10 -3
- package/dist/components/FieldMarkers/Label.js +1 -5
- package/dist/components/FieldMarkers/fieldmarkers-utils.js +13 -0
- package/dist/components/Fieldset/Fieldset.context.js +7 -0
- package/dist/components/Fieldset/Fieldset.d.ts +3 -1
- package/dist/components/Fieldset/Fieldset.js +34 -7
- package/dist/components/Pill/Pill.js +1 -1
- package/dist/components/Popover/Popover.js +1 -1
- package/dist/components/Radio/Radio.d.ts +1 -1
- package/dist/components/Radio/Radio.js +5 -3
- package/dist/components/Searchbox/Searchbox.js +2 -1
- package/dist/components/Select/Select.d.ts +3 -3
- package/dist/components/Select/Select.js +5 -3
- package/dist/components/Tag/Tag.js +1 -1
- package/dist/components/TextInput/TextInput.d.ts +3 -3
- package/dist/components/TextInput/TextInput.js +7 -3
- package/dist/components/Textarea/Textarea.d.ts +3 -3
- package/dist/components/Textarea/Textarea.js +5 -3
- package/dist/components/ValidationSummary/ValidationSummary.context.js +10 -0
- package/dist/components/ValidationSummary/ValidationSummary.d.ts +1 -8
- package/dist/components/ValidationSummary/ValidationSummary.js +36 -17
- package/dist/components/ValidationSummary/validationsummary-utils.d.ts +11 -0
- package/dist/components/ValidationSummary/validationsummary-utils.js +29 -6
- package/dist/hooks/useSlots.js +2 -26
- package/dist/types/index.d.ts +15 -0
- package/dist/utils/classes.d.ts +6 -0
- package/dist/utils/classes.js +13 -0
- package/dist/utils/index.d.ts +3 -7
- package/dist/utils/index.js +3 -17
- package/dist/utils/slots.d.ts +9 -0
- package/dist/utils/slots.js +37 -0
- package/package.json +3 -3
- package/src/components/Checkbox/Checkbox.tsx +8 -5
- package/src/components/Combobox/Combobox.context.ts +1 -0
- package/src/components/Combobox/Combobox.tsx +7 -3
- package/src/components/DatePicker/DatePicker.tsx +5 -3
- package/src/components/Field/Field.context.ts +14 -8
- package/src/components/Field/Field.tsx +39 -20
- package/src/components/FieldMarkers/Error.tsx +2 -1
- package/src/components/FieldMarkers/Label.tsx +0 -7
- package/src/components/FieldMarkers/fieldmarkers-utils.ts +26 -0
- package/src/components/Fieldset/Fieldset.context.ts +13 -0
- package/src/components/Fieldset/Fieldset.tsx +39 -5
- package/src/components/Radio/Radio.tsx +6 -3
- package/src/components/Select/Select.tsx +7 -4
- package/src/components/TextInput/TextInput.tsx +9 -8
- package/src/components/Textarea/Textarea.tsx +8 -7
- package/src/components/ValidationSummary/ValidationSummary.context.ts +18 -0
- package/src/components/ValidationSummary/ValidationSummary.tsx +38 -24
- package/src/components/ValidationSummary/validationsummary-utils.ts +81 -13
- package/src/hooks/useSlots.ts +1 -41
- package/src/utils/classes.ts +14 -0
- package/src/utils/index.ts +2 -24
- package/src/utils/slots.ts +63 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { LoadingSpinner } from "../LoadingSpinner/LoadingSpinner.js";
|
|
3
|
-
import { hasUserBg } from "../../utils/
|
|
3
|
+
import { hasUserBg } from "../../utils/classes.js";
|
|
4
4
|
import clsx from "clsx";
|
|
5
5
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
6
6
|
import React, { useCallback, useState } from "react";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Image } from "../Image/Image.js";
|
|
2
|
-
import { hasUserBg } from "../../utils/
|
|
2
|
+
import { hasUserBg } from "../../utils/classes.js";
|
|
3
3
|
import Picture_default from "../Picture/index.js";
|
|
4
4
|
import { useSlots } from "../../hooks/useSlots.js";
|
|
5
5
|
import clsx from "clsx";
|
|
@@ -10,15 +10,15 @@ export interface CheckboxProps extends Omit<InputHTMLAttributes<HTMLInputElement
|
|
|
10
10
|
error?: boolean;
|
|
11
11
|
/** Specify the component id. Will be auto-generated if not set. */
|
|
12
12
|
id?: string;
|
|
13
|
-
/** Specify the component name. */
|
|
14
|
-
name
|
|
13
|
+
/** Specify the component name. Without a name, the value is not submitted with a form. */
|
|
14
|
+
name?: string;
|
|
15
15
|
/** Specify a custom React ref for this component. */
|
|
16
16
|
ref?: Ref<HTMLInputElement>;
|
|
17
17
|
/** Specify the component size. */
|
|
18
18
|
size?: StandardSizes;
|
|
19
19
|
}
|
|
20
20
|
declare const Checkbox: {
|
|
21
|
-
({ className, disabled, error, id, name, ref, size, ...props }: CheckboxProps): JSX.Element;
|
|
21
|
+
({ "aria-describedby": ariaDescribedBy, className, disabled, error, id, name, ref, size, ...props }: CheckboxProps): JSX.Element;
|
|
22
22
|
slot: {
|
|
23
23
|
field: boolean;
|
|
24
24
|
inline: boolean;
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { useField } from "../Field/Field.context.js";
|
|
2
|
+
import { getDescribedBy, getFieldError, useField } from "../Field/Field.context.js";
|
|
3
3
|
import clsx from "clsx";
|
|
4
4
|
import { jsx } from "react/jsx-runtime";
|
|
5
5
|
//#region src/components/Checkbox/Checkbox.tsx
|
|
6
|
-
const Checkbox = ({ className, disabled, error
|
|
6
|
+
const Checkbox = ({ "aria-describedby": ariaDescribedBy, className, disabled, error, id, name, ref, size, ...props }) => {
|
|
7
7
|
const field = useField();
|
|
8
|
+
const hasError = getFieldError(error, field);
|
|
8
9
|
const componentProps = {
|
|
10
|
+
"aria-describedby": getDescribedBy(ariaDescribedBy, field),
|
|
11
|
+
"aria-invalid": hasError || void 0,
|
|
9
12
|
className: clsx("coop-checkbox", className),
|
|
10
|
-
"data-error": error || void 0,
|
|
11
13
|
"data-size": size ?? void 0,
|
|
12
14
|
disabled,
|
|
13
15
|
id: id ?? field?.id,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { ChevronDownIcon } from "../icons/ChevronDownIcon.js";
|
|
3
|
-
import { getSlotProp } from "../../utils/
|
|
3
|
+
import { getSlotProp } from "../../utils/slots.js";
|
|
4
4
|
import { useSlots } from "../../hooks/useSlots.js";
|
|
5
|
-
import { useField } from "../Field/Field.context.js";
|
|
5
|
+
import { getFieldError, useField } from "../Field/Field.context.js";
|
|
6
6
|
import { defaultFilter, defaultIsItemDisabled, defaultItemToString, normalizeOptions } from "./combobox-utils.js";
|
|
7
7
|
import { ComboboxContext, useComboboxContext } from "./Combobox.context.js";
|
|
8
8
|
import { TextInput } from "../TextInput/TextInput.js";
|
|
@@ -18,13 +18,14 @@ const componentSlots = {
|
|
|
18
18
|
const Combobox = ({ allowCustom = false, children, className, disabled, error, id, inputFilter, isItemDisabled, itemToString, onChange, onHighlight, onSelect, onStateChange, onToggle, openOnClick = true, ref, size, ...props }) => {
|
|
19
19
|
const field = useField();
|
|
20
20
|
const uid = id ?? field?.id;
|
|
21
|
+
const hasError = getFieldError(error, field);
|
|
21
22
|
const slots = useSlots(componentSlots, children);
|
|
22
23
|
const userOptions = getSlotProp(slots.ComboboxOptions, "options") ?? [];
|
|
23
24
|
const items = normalizeOptions(userOptions);
|
|
24
25
|
const [inputItems, setInputItems] = useState(items);
|
|
25
26
|
const componentProps = {
|
|
26
27
|
className: clsx("coop-combobox", className),
|
|
27
|
-
"data-
|
|
28
|
+
"data-field": "",
|
|
28
29
|
"data-size": size ?? void 0,
|
|
29
30
|
id: uid,
|
|
30
31
|
...props
|
|
@@ -74,6 +75,7 @@ const Combobox = ({ allowCustom = false, children, className, disabled, error, i
|
|
|
74
75
|
return /* @__PURE__ */ jsx(ComboboxContext.Provider, {
|
|
75
76
|
value: {
|
|
76
77
|
disabled,
|
|
78
|
+
error: hasError,
|
|
77
79
|
items: inputItems,
|
|
78
80
|
props: comboboxProps,
|
|
79
81
|
size
|
|
@@ -90,6 +92,7 @@ const ComboboxInput = ({ className, placeholder, ...props }) => {
|
|
|
90
92
|
const componentProps = {
|
|
91
93
|
className,
|
|
92
94
|
disabled: combobox.disabled,
|
|
95
|
+
error: combobox.error,
|
|
93
96
|
placeholder,
|
|
94
97
|
size: combobox.size,
|
|
95
98
|
...props
|
|
@@ -3,7 +3,7 @@ import { CalendarIcon } from "../icons/CalendarIcon.js";
|
|
|
3
3
|
import { CrossIcon } from "../icons/CrossIcon.js";
|
|
4
4
|
import { TickIcon } from "../icons/TickIcon.js";
|
|
5
5
|
import { Button } from "../Button/Button.js";
|
|
6
|
-
import { useField } from "../Field/Field.context.js";
|
|
6
|
+
import { getFieldError, useField } from "../Field/Field.context.js";
|
|
7
7
|
import { TextInput } from "../TextInput/TextInput.js";
|
|
8
8
|
import { Popover } from "../Popover/Popover.js";
|
|
9
9
|
import { getDateValues, getDefaultMonth, getEndDate, getInitialDate, getStartDate, shouldClose, shouldSkipParsing } from "./datepicker-utils.js";
|
|
@@ -45,8 +45,9 @@ const Calendar = ({ captionLayout = "label", className, disabled, endMonth, form
|
|
|
45
45
|
...props
|
|
46
46
|
});
|
|
47
47
|
};
|
|
48
|
-
const DatePicker = ({ className, closeOnSelect = true, dateFormat = "dd/MM/yyyy", disabled, disabledDates, endDate, error
|
|
48
|
+
const DatePicker = ({ className, closeOnSelect = true, dateFormat = "dd/MM/yyyy", disabled, disabledDates, endDate, error, id, initialDate = now, initialSelected = false, mode = "single", name, onChange, onSelect, ref, required = false, size, startDate, ...props }) => {
|
|
49
49
|
const field = useField();
|
|
50
|
+
const hasError = getFieldError(error, field);
|
|
50
51
|
initialDate = getInitialDate(mode, initialDate);
|
|
51
52
|
const startDateProp = startDate;
|
|
52
53
|
const endDateProp = endDate;
|
|
@@ -112,7 +113,7 @@ const DatePicker = ({ className, closeOnSelect = true, dateFormat = "dd/MM/yyyy"
|
|
|
112
113
|
const componentProps = {
|
|
113
114
|
className: clsx("coop-datepicker", className),
|
|
114
115
|
"data-disabled": disabled ?? void 0,
|
|
115
|
-
"data-
|
|
116
|
+
"data-field": "",
|
|
116
117
|
"data-mode": mode,
|
|
117
118
|
...props
|
|
118
119
|
};
|
|
@@ -165,6 +166,7 @@ const DatePicker = ({ className, closeOnSelect = true, dateFormat = "dd/MM/yyyy"
|
|
|
165
166
|
autoComplete: "off",
|
|
166
167
|
className: "coop-datepicker-input",
|
|
167
168
|
disabled,
|
|
169
|
+
error: hasError,
|
|
168
170
|
id: valueProps.id + "_display",
|
|
169
171
|
name: name + "_display",
|
|
170
172
|
onChange: updateFromInput,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { CrossIcon } from "../icons/CrossIcon.js";
|
|
3
|
-
import { hasUserBg } from "../../utils/
|
|
3
|
+
import { hasUserBg } from "../../utils/classes.js";
|
|
4
4
|
import clsx from "clsx";
|
|
5
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
6
|
import { createContext, useContext, useEffect, useRef } from "react";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ChevronDownIcon } from "../icons/ChevronDownIcon.js";
|
|
2
|
-
import { hasUserBg } from "../../utils/
|
|
2
|
+
import { hasUserBg } from "../../utils/classes.js";
|
|
3
3
|
import { useSlots } from "../../hooks/useSlots.js";
|
|
4
4
|
import clsx from "clsx";
|
|
5
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
import { joinIds } from "../FieldMarkers/fieldmarkers-utils.js";
|
|
2
3
|
import { createContext, useContext } from "react";
|
|
3
4
|
//#region src/components/Field/Field.context.ts
|
|
4
5
|
const FieldContext = createContext(null);
|
|
5
|
-
const useField = () =>
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
return context;
|
|
9
|
-
};
|
|
6
|
+
const useField = () => useContext(FieldContext);
|
|
7
|
+
const getDescribedBy = (describedBy, field) => joinIds(field?.describedBy, describedBy);
|
|
8
|
+
const getFieldError = (error, field) => error ?? field?.error ?? false;
|
|
10
9
|
//#endregion
|
|
11
|
-
export { FieldContext, useField };
|
|
10
|
+
export { FieldContext, getDescribedBy, getFieldError, useField };
|
|
@@ -12,7 +12,7 @@ interface FieldProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
12
12
|
children?: React.ReactNode;
|
|
13
13
|
/** Specify additional CSS classes. */
|
|
14
14
|
classname?: string;
|
|
15
|
-
/** Specify the component error state. */
|
|
15
|
+
/** Specify the component error state. Inherits the error state of a Fieldset with `group` set when not specified. */
|
|
16
16
|
error?: boolean;
|
|
17
17
|
/** Specify whether the Field should show the left-hand error bar if it is in an error state. */
|
|
18
18
|
hideErrorBar?: boolean;
|
|
@@ -20,7 +20,7 @@ interface FieldProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
20
20
|
ref?: Ref<HTMLDivElement>;
|
|
21
21
|
}
|
|
22
22
|
declare const Field: {
|
|
23
|
-
({ boxed, children, className, error, hideErrorBar, ref, ...props }: FieldProps): JSX.Element;
|
|
23
|
+
({ boxed, children, className, error: errorProp, hideErrorBar, ref, ...props }: FieldProps): JSX.Element;
|
|
24
24
|
slot: {
|
|
25
25
|
name: string;
|
|
26
26
|
};
|
|
@@ -1,32 +1,35 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useId as useId$1 } from "../../hooks/useId.js";
|
|
3
|
-
import { getSlotProp } from "../../utils/
|
|
4
|
-
import {
|
|
3
|
+
import { forEachSlot, getSlotProp } from "../../utils/slots.js";
|
|
4
|
+
import { getMarkerIds } from "../FieldMarkers/fieldmarkers-utils.js";
|
|
5
|
+
import { FieldContext, useField } from "./Field.context.js";
|
|
5
6
|
import { Error } from "../FieldMarkers/Error.js";
|
|
6
7
|
import { Hint } from "../FieldMarkers/Hint.js";
|
|
7
8
|
import { Label } from "../FieldMarkers/Label.js";
|
|
9
|
+
import { useFieldset } from "../Fieldset/Fieldset.context.js";
|
|
8
10
|
import clsx from "clsx";
|
|
9
11
|
import { jsx } from "react/jsx-runtime";
|
|
10
12
|
import "react";
|
|
11
13
|
//#region src/components/Field/Field.tsx
|
|
12
|
-
const Field = ({ boxed = false, children, className, error
|
|
14
|
+
const Field = ({ boxed = false, children, className, error: errorProp, hideErrorBar = false, ref, ...props }) => {
|
|
15
|
+
const internalId = useId$1();
|
|
16
|
+
const fieldset = useFieldset();
|
|
17
|
+
const error = errorProp ?? fieldset?.error ?? false;
|
|
13
18
|
const controlProps = {
|
|
14
19
|
disabled: false,
|
|
15
|
-
id:
|
|
20
|
+
id: internalId
|
|
16
21
|
};
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
}
|
|
22
|
+
const markers = {};
|
|
23
|
+
forEachSlot(children, (slot, child) => {
|
|
24
|
+
if (slot.field) {
|
|
25
|
+
controlProps.inline = slot.inline ?? false;
|
|
26
|
+
controlProps.disabled = getSlotProp(child, "disabled") ?? false;
|
|
27
|
+
controlProps.id = getSlotProp(child, "id") ?? controlProps.id;
|
|
28
|
+
controlProps.suffix = slot.suffix ?? void 0;
|
|
29
|
+
} else if (slot.name === "FieldHint") markers.hint = { id: getSlotProp(child, "id") };
|
|
30
|
+
else if (slot.name === "FieldError") markers.error = { id: getSlotProp(child, "id") };
|
|
29
31
|
});
|
|
32
|
+
const markerIds = getMarkerIds(markers, controlProps.id);
|
|
30
33
|
const componentProps = {
|
|
31
34
|
...props,
|
|
32
35
|
"aria-disabled": controlProps.disabled || void 0,
|
|
@@ -36,7 +39,11 @@ const Field = ({ boxed = false, children, className, error = false, hideErrorBar
|
|
|
36
39
|
"data-hide-error": hideErrorBar || void 0
|
|
37
40
|
};
|
|
38
41
|
return /* @__PURE__ */ jsx(FieldContext.Provider, {
|
|
39
|
-
value: {
|
|
42
|
+
value: {
|
|
43
|
+
...controlProps,
|
|
44
|
+
...markerIds,
|
|
45
|
+
error
|
|
46
|
+
},
|
|
40
47
|
children: /* @__PURE__ */ jsx("div", {
|
|
41
48
|
...componentProps,
|
|
42
49
|
ref,
|
|
@@ -44,9 +51,22 @@ const Field = ({ boxed = false, children, className, error = false, hideErrorBar
|
|
|
44
51
|
})
|
|
45
52
|
});
|
|
46
53
|
};
|
|
47
|
-
const FieldLabel = (props) =>
|
|
48
|
-
const
|
|
49
|
-
|
|
54
|
+
const FieldLabel = (props) => {
|
|
55
|
+
const field = useField();
|
|
56
|
+
return /* @__PURE__ */ jsx(Label, {
|
|
57
|
+
htmlFor: field ? field.id + (field.suffix ?? "") : void 0,
|
|
58
|
+
id: field ? `${field.id}_label` : void 0,
|
|
59
|
+
...props
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
const FieldHint = (props) => /* @__PURE__ */ jsx(Hint, {
|
|
63
|
+
id: useField()?.hintId,
|
|
64
|
+
...props
|
|
65
|
+
});
|
|
66
|
+
const FieldError = (props) => /* @__PURE__ */ jsx(Error, {
|
|
67
|
+
id: useField()?.errorId,
|
|
68
|
+
...props
|
|
69
|
+
});
|
|
50
70
|
Field.slot = { name: "Field" };
|
|
51
71
|
FieldLabel.slot = { name: "FieldLabel" };
|
|
52
72
|
FieldHint.slot = { name: "FieldHint" };
|
|
@@ -1,15 +1,22 @@
|
|
|
1
1
|
import clsx from "clsx";
|
|
2
|
-
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
//#region src/components/FieldMarkers/Error.tsx
|
|
4
4
|
const Error = ({ children, className, ref, ...props }) => {
|
|
5
5
|
const componentProps = {
|
|
6
6
|
className: clsx("coop-field-error ", className),
|
|
7
7
|
...props
|
|
8
8
|
};
|
|
9
|
-
return /* @__PURE__ */
|
|
9
|
+
return /* @__PURE__ */ jsxs("span", {
|
|
10
10
|
...componentProps,
|
|
11
11
|
ref,
|
|
12
|
-
children
|
|
12
|
+
children: [
|
|
13
|
+
/* @__PURE__ */ jsx("span", {
|
|
14
|
+
className: "sr-only",
|
|
15
|
+
children: "Error:"
|
|
16
|
+
}),
|
|
17
|
+
" ",
|
|
18
|
+
children
|
|
19
|
+
]
|
|
13
20
|
});
|
|
14
21
|
};
|
|
15
22
|
//#endregion
|
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
import { useField } from "../Field/Field.context.js";
|
|
2
1
|
import clsx from "clsx";
|
|
3
2
|
import { jsx } from "react/jsx-runtime";
|
|
4
3
|
//#region src/components/FieldMarkers/Label.tsx
|
|
5
|
-
const Label = ({ children, className,
|
|
6
|
-
const field = useField();
|
|
4
|
+
const Label = ({ children, className, isVisible = true, ref, ...props }) => {
|
|
7
5
|
const componentProps = {
|
|
8
6
|
className: clsx("coop-field-label", !isVisible && "sr-only", className),
|
|
9
|
-
htmlFor: htmlFor ?? (field?.id ? field.id + (field?.suffix ?? "") : void 0),
|
|
10
|
-
id: id ?? (field?.id ? field.id + "_label" : void 0),
|
|
11
7
|
...props
|
|
12
8
|
};
|
|
13
9
|
return /* @__PURE__ */ jsx("label", {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region src/components/FieldMarkers/fieldmarkers-utils.ts
|
|
2
|
+
const joinIds = (...ids) => ids.filter(Boolean).join(" ") || void 0;
|
|
3
|
+
const getMarkerIds = (markers, baseId) => {
|
|
4
|
+
const hintId = markers.hint?.id ?? `${baseId}_hint`;
|
|
5
|
+
const errorId = markers.error?.id ?? `${baseId}_error`;
|
|
6
|
+
return {
|
|
7
|
+
describedBy: joinIds(markers.hint && hintId, markers.error && errorId),
|
|
8
|
+
errorId,
|
|
9
|
+
hintId
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
//#endregion
|
|
13
|
+
export { getMarkerIds, joinIds };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { createContext, useContext } from "react";
|
|
3
|
+
//#region src/components/Fieldset/Fieldset.context.ts
|
|
4
|
+
const FieldsetContext = createContext(null);
|
|
5
|
+
const useFieldset = () => useContext(FieldsetContext);
|
|
6
|
+
//#endregion
|
|
7
|
+
export { FieldsetContext, useFieldset };
|
|
@@ -14,13 +14,15 @@ export interface FieldsetProps extends FieldsetHTMLAttributes<HTMLFieldSetElemen
|
|
|
14
14
|
disabled?: boolean;
|
|
15
15
|
/** Specify the component error state. */
|
|
16
16
|
error?: boolean;
|
|
17
|
+
/** Specify whether the Fieldset is a single question, such as a group of Radio inputs. Fields inside inherit its error state. */
|
|
18
|
+
group?: boolean;
|
|
17
19
|
/** Specify whether the Fieldset should show the left-hand error bar if it is in an error state. */
|
|
18
20
|
hideErrorBar?: boolean;
|
|
19
21
|
/** Specify a custom React ref for this component. */
|
|
20
22
|
ref?: Ref<HTMLFieldSetElement>;
|
|
21
23
|
}
|
|
22
24
|
declare const Fieldset: {
|
|
23
|
-
({ children, className, disabled, error, hideErrorBar, ref, ...props }: FieldsetProps): JSX.Element;
|
|
25
|
+
({ "aria-describedby": ariaDescribedBy, children, className, disabled, error, group, hideErrorBar, id, ref, ...props }: FieldsetProps): JSX.Element;
|
|
24
26
|
slot: {
|
|
25
27
|
name: string;
|
|
26
28
|
};
|
|
@@ -1,22 +1,43 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useId } from "../../hooks/useId.js";
|
|
3
|
+
import { forEachSlot, getSlotProp } from "../../utils/slots.js";
|
|
4
|
+
import { getMarkerIds, joinIds } from "../FieldMarkers/fieldmarkers-utils.js";
|
|
1
5
|
import { Error } from "../FieldMarkers/Error.js";
|
|
2
6
|
import { Hint } from "../FieldMarkers/Hint.js";
|
|
7
|
+
import { FieldsetContext, useFieldset } from "./Fieldset.context.js";
|
|
3
8
|
import { Legend } from "../FieldMarkers/Legend.js";
|
|
4
9
|
import clsx from "clsx";
|
|
5
10
|
import { jsx } from "react/jsx-runtime";
|
|
6
11
|
//#region src/components/Fieldset/Fieldset.tsx
|
|
7
|
-
const Fieldset = ({ children, className, disabled, error = false, hideErrorBar = false, ref, ...props }) => {
|
|
12
|
+
const Fieldset = ({ "aria-describedby": ariaDescribedBy, children, className, disabled, error = false, group = false, hideErrorBar = false, id, ref, ...props }) => {
|
|
13
|
+
const uid = useId(id);
|
|
14
|
+
const markers = {};
|
|
15
|
+
forEachSlot(children, (slot, child) => {
|
|
16
|
+
if (slot.name === "FieldsetHint") markers.hint = { id: getSlotProp(child, "id") };
|
|
17
|
+
else if (slot.name === "FieldsetError") markers.error = { id: getSlotProp(child, "id") };
|
|
18
|
+
});
|
|
19
|
+
const { describedBy, errorId, hintId } = getMarkerIds(markers, uid);
|
|
8
20
|
const componentProps = {
|
|
21
|
+
"aria-describedby": joinIds(describedBy, ariaDescribedBy),
|
|
9
22
|
"aria-disabled": disabled,
|
|
10
23
|
className: clsx("coop-fieldset", className),
|
|
11
24
|
"data-error": error || void 0,
|
|
12
25
|
"data-hide-error": hideErrorBar || void 0,
|
|
13
26
|
disabled,
|
|
27
|
+
id,
|
|
14
28
|
...props
|
|
15
29
|
};
|
|
16
|
-
return /* @__PURE__ */ jsx(
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
30
|
+
return /* @__PURE__ */ jsx(FieldsetContext.Provider, {
|
|
31
|
+
value: {
|
|
32
|
+
error: group && error,
|
|
33
|
+
errorId,
|
|
34
|
+
hintId
|
|
35
|
+
},
|
|
36
|
+
children: /* @__PURE__ */ jsx("fieldset", {
|
|
37
|
+
...componentProps,
|
|
38
|
+
ref,
|
|
39
|
+
children
|
|
40
|
+
})
|
|
20
41
|
});
|
|
21
42
|
};
|
|
22
43
|
const FieldsetFields = ({ children, className, orientation = "vertical", ...props }) => {
|
|
@@ -31,8 +52,14 @@ const FieldsetFields = ({ children, className, orientation = "vertical", ...prop
|
|
|
31
52
|
});
|
|
32
53
|
};
|
|
33
54
|
const FieldsetLegend = (props) => /* @__PURE__ */ jsx(Legend, { ...props });
|
|
34
|
-
const FieldsetHint = (props) => /* @__PURE__ */ jsx(Hint, {
|
|
35
|
-
|
|
55
|
+
const FieldsetHint = (props) => /* @__PURE__ */ jsx(Hint, {
|
|
56
|
+
id: useFieldset()?.hintId,
|
|
57
|
+
...props
|
|
58
|
+
});
|
|
59
|
+
const FieldsetError = (props) => /* @__PURE__ */ jsx(Error, {
|
|
60
|
+
id: useFieldset()?.errorId,
|
|
61
|
+
...props
|
|
62
|
+
});
|
|
36
63
|
Fieldset.slot = { name: "Fieldset" };
|
|
37
64
|
FieldsetFields.slot = { name: "FieldsetField" };
|
|
38
65
|
FieldsetLegend.slot = { name: "FieldsetLegend" };
|
|
@@ -18,7 +18,7 @@ export interface RadioProps extends Omit<InputHTMLAttributes<HTMLInputElement>,
|
|
|
18
18
|
size?: StandardSizes;
|
|
19
19
|
}
|
|
20
20
|
declare const Radio: {
|
|
21
|
-
({ className, disabled, error, id, name, ref, size, ...props }: RadioProps): JSX.Element;
|
|
21
|
+
({ "aria-describedby": ariaDescribedBy, className, disabled, error, id, name, ref, size, ...props }: RadioProps): JSX.Element;
|
|
22
22
|
slot: {
|
|
23
23
|
field: boolean;
|
|
24
24
|
inline: boolean;
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { useField } from "../Field/Field.context.js";
|
|
2
|
+
import { getDescribedBy, getFieldError, useField } from "../Field/Field.context.js";
|
|
3
3
|
import clsx from "clsx";
|
|
4
4
|
import { jsx } from "react/jsx-runtime";
|
|
5
5
|
//#region src/components/Radio/Radio.tsx
|
|
6
|
-
const Radio = ({ className, disabled, error
|
|
6
|
+
const Radio = ({ "aria-describedby": ariaDescribedBy, className, disabled, error, id, name, ref, size, ...props }) => {
|
|
7
7
|
const field = useField();
|
|
8
|
+
const hasError = getFieldError(error, field);
|
|
8
9
|
const componentProps = {
|
|
10
|
+
"aria-describedby": getDescribedBy(ariaDescribedBy, field),
|
|
11
|
+
"aria-invalid": hasError || void 0,
|
|
9
12
|
className: clsx("coop-radio", className),
|
|
10
|
-
"data-error": error || void 0,
|
|
11
13
|
"data-size": size ?? void 0,
|
|
12
14
|
disabled,
|
|
13
15
|
id: id ?? field?.id,
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useId as useId$1 } from "../../hooks/useId.js";
|
|
3
3
|
import { SearchIcon } from "../icons/SearchIcon.js";
|
|
4
|
-
import {
|
|
4
|
+
import { hasUserBorder } from "../../utils/classes.js";
|
|
5
|
+
import { getSlotProp } from "../../utils/slots.js";
|
|
5
6
|
import { Button } from "../Button/Button.js";
|
|
6
7
|
import { useSlots } from "../../hooks/useSlots.js";
|
|
7
8
|
import TextInput_default from "../TextInput/index.js";
|
|
@@ -19,8 +19,8 @@ export interface SelectProps extends Omit<SelectHTMLAttributes<HTMLSelectElement
|
|
|
19
19
|
fit?: boolean;
|
|
20
20
|
/** Specify the component id. Will be auto-generated if not set. */
|
|
21
21
|
id?: string;
|
|
22
|
-
/** Specify the Select name. */
|
|
23
|
-
name
|
|
22
|
+
/** Specify the Select name. Without a name, the value is not submitted with a form. */
|
|
23
|
+
name?: string;
|
|
24
24
|
/** Specify a custom React ref for this component. */
|
|
25
25
|
ref?: Ref<HTMLSelectElement>;
|
|
26
26
|
/** Specify the component size. */
|
|
@@ -39,7 +39,7 @@ interface SelectOptionProps extends OptionHTMLAttributes<HTMLOptionElement> {
|
|
|
39
39
|
className?: string;
|
|
40
40
|
}
|
|
41
41
|
declare const Select: {
|
|
42
|
-
({ children, className, disabled, error, fit, id, name, ref, size, ...props }: SelectProps): JSX.Element;
|
|
42
|
+
({ "aria-describedby": ariaDescribedBy, children, className, disabled, error, fit, id, name, ref, size, ...props }: SelectProps): JSX.Element;
|
|
43
43
|
slot: {
|
|
44
44
|
field: boolean;
|
|
45
45
|
name: string;
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { useField } from "../Field/Field.context.js";
|
|
2
|
+
import { getDescribedBy, getFieldError, useField } from "../Field/Field.context.js";
|
|
3
3
|
import clsx from "clsx";
|
|
4
4
|
import { jsx } from "react/jsx-runtime";
|
|
5
5
|
//#region src/components/Select/Select.tsx
|
|
6
|
-
const Select = ({ children, className, disabled, error, fit = false, id, name, ref, size, ...props }) => {
|
|
6
|
+
const Select = ({ "aria-describedby": ariaDescribedBy, children, className, disabled, error, fit = false, id, name, ref, size, ...props }) => {
|
|
7
7
|
const field = useField();
|
|
8
|
+
const hasError = getFieldError(error, field);
|
|
8
9
|
const componentProps = {
|
|
10
|
+
"aria-describedby": getDescribedBy(ariaDescribedBy, field),
|
|
11
|
+
"aria-invalid": hasError || void 0,
|
|
9
12
|
className: clsx("coop-select", className),
|
|
10
|
-
"data-error": error ?? void 0,
|
|
11
13
|
"data-fit": fit || void 0,
|
|
12
14
|
"data-size": size ?? void 0,
|
|
13
15
|
disabled,
|
|
@@ -15,8 +15,8 @@ export interface TextInputProps extends Omit<InputHTMLAttributes<HTMLInputElemen
|
|
|
15
15
|
fit?: boolean;
|
|
16
16
|
/** Specify the component id. Will be auto-generated if not set. */
|
|
17
17
|
id?: string;
|
|
18
|
-
/** Specify the component name. */
|
|
19
|
-
name
|
|
18
|
+
/** Specify the component name. Without a name, the value is not submitted with a form. */
|
|
19
|
+
name?: string;
|
|
20
20
|
/** Specify placeholder text. Do not use in place of a form label. */
|
|
21
21
|
placeholder?: string;
|
|
22
22
|
/** Specify the prefix. */
|
|
@@ -35,7 +35,7 @@ export interface TextInputProps extends Omit<InputHTMLAttributes<HTMLInputElemen
|
|
|
35
35
|
type?: "text" | "email" | "number" | "password" | "search" | "tel" | "url" | "date" | "datetime-local" | "week" | "month" | "time";
|
|
36
36
|
}
|
|
37
37
|
declare const TextInput: {
|
|
38
|
-
({ className, disabled, error, fit, id, name, placeholder, prefix, prefixInline, ref, size, suffix, suffixInline, type, ...props }: TextInputProps): JSX.Element;
|
|
38
|
+
({ "aria-describedby": ariaDescribedBy, className, disabled, error, fit, id, name, placeholder, prefix, prefixInline, ref, size, suffix, suffixInline, type, ...props }: TextInputProps): JSX.Element;
|
|
39
39
|
slot: {
|
|
40
40
|
field: boolean;
|
|
41
41
|
name: string;
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { useField } from "../Field/Field.context.js";
|
|
2
|
+
import { getDescribedBy, getFieldError, useField } from "../Field/Field.context.js";
|
|
3
3
|
import clsx from "clsx";
|
|
4
4
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
5
|
//#region src/components/TextInput/TextInput.tsx
|
|
6
|
-
const TextInput = ({ className, disabled, error
|
|
6
|
+
const TextInput = ({ "aria-describedby": ariaDescribedBy, className, disabled, error, fit = false, id, name, placeholder, prefix, prefixInline = false, ref, size, suffix, suffixInline = false, type = "text", ...props }) => {
|
|
7
7
|
const field = useField();
|
|
8
|
+
const hasError = getFieldError(error, field);
|
|
8
9
|
const componentProps = {
|
|
10
|
+
"aria-describedby": getDescribedBy(ariaDescribedBy, field),
|
|
11
|
+
"aria-invalid": hasError || void 0,
|
|
9
12
|
className: clsx("coop-text-input", className),
|
|
10
|
-
"data-error": error || void 0,
|
|
11
13
|
"data-fit": fit || void 0,
|
|
12
14
|
"data-size": size ?? void 0,
|
|
13
15
|
disabled,
|
|
@@ -27,6 +29,8 @@ const TextInput = ({ className, disabled, error = false, fit = false, id, name,
|
|
|
27
29
|
} : {};
|
|
28
30
|
return prefix || suffix ? /* @__PURE__ */ jsxs("div", {
|
|
29
31
|
className: "coop-text-input-wrapper",
|
|
32
|
+
"data-field": "",
|
|
33
|
+
"data-size": size,
|
|
30
34
|
children: [
|
|
31
35
|
prefix && /* @__PURE__ */ jsx("span", {
|
|
32
36
|
...prefixProps,
|
|
@@ -27,8 +27,8 @@ export interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElemen
|
|
|
27
27
|
fit?: boolean;
|
|
28
28
|
/** Specify the component id. Will be auto-generated if not set. */
|
|
29
29
|
id?: string;
|
|
30
|
-
/** Specify the component name. */
|
|
31
|
-
name
|
|
30
|
+
/** Specify the component name. Without a name, the value is not submitted with a form. */
|
|
31
|
+
name?: string;
|
|
32
32
|
/** Specify placeholder text. Do not use in place of a form label. */
|
|
33
33
|
placeholder?: string;
|
|
34
34
|
/** Specify a custom React ref for this component. */
|
|
@@ -42,7 +42,7 @@ export interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElemen
|
|
|
42
42
|
size?: StandardSizes;
|
|
43
43
|
}
|
|
44
44
|
declare const Textarea: {
|
|
45
|
-
({ className, cols, counter, cutoff, disabled, error, fit, id, maxLength, name, onChange: userOnChange, placeholder, ref, rows, size, ...props }: TextareaProps): JSX.Element;
|
|
45
|
+
({ "aria-describedby": ariaDescribedBy, className, cols, counter, cutoff, disabled, error, fit, id, maxLength, name, onChange: userOnChange, placeholder, ref, rows, size, ...props }: TextareaProps): JSX.Element;
|
|
46
46
|
slot: {
|
|
47
47
|
field: boolean;
|
|
48
48
|
name: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { useField } from "../Field/Field.context.js";
|
|
2
|
+
import { getDescribedBy, getFieldError, useField } from "../Field/Field.context.js";
|
|
3
3
|
import { useDebounce } from "../../hooks/useDebounce.js";
|
|
4
4
|
import clsx from "clsx";
|
|
5
5
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -9,12 +9,14 @@ const DEBOUNCE_DELAY = 750;
|
|
|
9
9
|
const charCountMessage = (remaining) => {
|
|
10
10
|
return `You have ${Math.abs(remaining).toLocaleString()} ${Math.abs(remaining) === 1 ? "character" : "characters"} ${remaining < 0 ? "too many" : "remaining"}`;
|
|
11
11
|
};
|
|
12
|
-
const Textarea = ({ className, cols = 30, counter = false, cutoff = false, disabled = false, error
|
|
12
|
+
const Textarea = ({ "aria-describedby": ariaDescribedBy, className, cols = 30, counter = false, cutoff = false, disabled = false, error, fit = false, id, maxLength, name, onChange: userOnChange, placeholder, ref, rows = 4, size, ...props }) => {
|
|
13
13
|
const field = useField();
|
|
14
|
+
const hasError = getFieldError(error, field);
|
|
14
15
|
const componentProps = {
|
|
16
|
+
"aria-describedby": getDescribedBy(ariaDescribedBy, field),
|
|
17
|
+
"aria-invalid": hasError || void 0,
|
|
15
18
|
className: clsx("coop-textarea", className),
|
|
16
19
|
cols,
|
|
17
|
-
"data-error": error ?? void 0,
|
|
18
20
|
"data-fit": fit || void 0,
|
|
19
21
|
"data-size": size ?? void 0,
|
|
20
22
|
disabled,
|