@luscii-healthtech/web-ui 2.0.0 → 2.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.
- package/dist/components/Accordion/Accordion.d.ts +10 -0
- package/dist/components/Accordion/AccordionItem.d.ts +9 -0
- package/dist/components/Form/Form.d.ts +9 -0
- package/dist/components/Form/FormFieldDecorator.d.ts +8 -0
- package/dist/components/Form/FormInput.d.ts +3 -0
- package/dist/components/Form/FormRadioGroup.d.ts +3 -0
- package/dist/components/Form/FormSelect.d.ts +3 -0
- package/dist/components/Form/form.transformer.d.ts +20 -0
- package/dist/components/Form/form.types.d.ts +54 -0
- package/dist/components/Input/Input.d.ts +8 -7
- package/dist/components/Input/SearchInput.d.ts +1 -1
- package/dist/components/List/List.d.ts +1 -1
- package/dist/components/List/List.types.d.ts +1 -0
- package/dist/components/List/ListItemSkeleton.d.ts +2 -0
- package/dist/components/List/ListSkeleton.d.ts +7 -0
- package/dist/components/Radio/Radio.d.ts +3 -0
- package/dist/components/Radio/RadioV2.d.ts +17 -0
- package/dist/components/RadioGroup/RadioGroup.d.ts +3 -0
- package/dist/components/RadioGroup/RadioGroupV2.d.ts +9 -0
- package/dist/components/Select/Select.d.ts +3 -0
- package/dist/components/Select/SelectV2.d.ts +31 -0
- package/dist/index.d.ts +2 -0
- package/dist/web-ui-tailwind.css +50 -0
- package/dist/web-ui.cjs.development.js +604 -40
- package/dist/web-ui.cjs.development.js.map +1 -1
- package/dist/web-ui.cjs.production.min.js +1 -1
- package/dist/web-ui.cjs.production.min.js.map +1 -1
- package/dist/web-ui.esm.js +604 -41
- package/dist/web-ui.esm.js.map +1 -1
- package/package.json +6 -3
- package/src/components/Accordion/Accordion.tsx +33 -0
- package/src/components/Accordion/AccordionItem.tsx +50 -0
- package/src/components/Form/Form.tsx +106 -0
- package/src/components/Form/FormFieldDecorator.tsx +66 -0
- package/src/components/Form/FormInput.tsx +47 -0
- package/src/components/Form/FormRadioGroup.tsx +23 -0
- package/src/components/Form/FormSelect.tsx +32 -0
- package/src/components/Form/form.transformer.ts +9 -0
- package/src/components/Form/form.types.ts +132 -0
- package/src/components/Input/Input.tsx +160 -165
- package/src/components/Input/SearchInput.tsx +13 -3
- package/src/components/List/List.tsx +13 -9
- package/src/components/List/List.types.ts +1 -0
- package/src/components/List/ListItemSkeleton.tsx +26 -0
- package/src/components/List/ListSkeleton.scss +5 -0
- package/src/components/List/ListSkeleton.tsx +30 -0
- package/src/components/Radio/Radio.js +3 -0
- package/src/components/Radio/RadioV2.css +15 -0
- package/src/components/Radio/RadioV2.tsx +87 -0
- package/src/components/RadioGroup/RadioGroup.js +3 -0
- package/src/components/RadioGroup/RadioGroupV2.tsx +35 -0
- package/src/components/Select/Select.tsx +38 -12
- package/src/components/Select/SelectV2.tsx +171 -0
- package/src/index.tsx +3 -0
- package/src/styles/_skeleton.scss +63 -0
- package/src/types/general.types.ts +1 -1
- package/src/components/Select/Select.examples.md +0 -161
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "2.
|
|
2
|
+
"version": "2.3.0",
|
|
3
3
|
"license": "MIT",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"typings": "dist/index.d.ts",
|
|
@@ -82,6 +82,7 @@
|
|
|
82
82
|
"postcss": "^8.4.14",
|
|
83
83
|
"postcss-loader": "4.2",
|
|
84
84
|
"postcss-url": "^10.1.3",
|
|
85
|
+
"prettier": "^2.7.1",
|
|
85
86
|
"react": "^18.2.0",
|
|
86
87
|
"react-dom": "^18.2.0",
|
|
87
88
|
"react-is": "^18.2.0",
|
|
@@ -103,6 +104,7 @@
|
|
|
103
104
|
"dependencies": {
|
|
104
105
|
"@fontsource/inter": "^4.5.11",
|
|
105
106
|
"@fontsource/roboto": "^4.5.7",
|
|
107
|
+
"@hookform/error-message": "^2.0.0",
|
|
106
108
|
"@reach/router": "^1.3.4",
|
|
107
109
|
"@typescript-eslint/eslint-plugin": "^5.29.0",
|
|
108
110
|
"classnames": "^2.3.1",
|
|
@@ -118,11 +120,12 @@
|
|
|
118
120
|
"path": "^0.12.7",
|
|
119
121
|
"react-datepicker": "^4.8.0",
|
|
120
122
|
"react-draft-wysiwyg": "^1.14.7",
|
|
123
|
+
"react-dragula": "^1.1.17",
|
|
121
124
|
"react-glider": "^3.1.0",
|
|
125
|
+
"react-hook-form": "^7.33.0",
|
|
122
126
|
"react-modal": "^3.15.1",
|
|
123
127
|
"react-quill": "^1.3.5",
|
|
124
|
-
"react-select": "^5.3.2"
|
|
125
|
-
"react-dragula": "^1.1.17"
|
|
128
|
+
"react-select": "^5.3.2"
|
|
126
129
|
},
|
|
127
130
|
"browserslist": [
|
|
128
131
|
"last 1 chrome version",
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
import { AccordionItem, AccordionItemProps } from "./AccordionItem";
|
|
4
|
+
|
|
5
|
+
export interface AccordionProps {
|
|
6
|
+
dataTestId?: string;
|
|
7
|
+
items: AccordionItemProps[];
|
|
8
|
+
className?: string;
|
|
9
|
+
isCollapsedByDefault?: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const Accordion: React.VFC<AccordionProps> = ({
|
|
13
|
+
dataTestId,
|
|
14
|
+
isCollapsedByDefault = false,
|
|
15
|
+
items,
|
|
16
|
+
className,
|
|
17
|
+
}) => {
|
|
18
|
+
return (
|
|
19
|
+
<ul data-test-id={dataTestId} className={className}>
|
|
20
|
+
{items.map?.((item) => (
|
|
21
|
+
<AccordionItem
|
|
22
|
+
{...item}
|
|
23
|
+
key={item.id}
|
|
24
|
+
isCollapsedByDefault={
|
|
25
|
+
item.isCollapsedByDefault ?? isCollapsedByDefault
|
|
26
|
+
}
|
|
27
|
+
/>
|
|
28
|
+
))}
|
|
29
|
+
</ul>
|
|
30
|
+
);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export default Accordion;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import React, { useReducer } from "react";
|
|
2
|
+
import classNames from "classnames";
|
|
3
|
+
|
|
4
|
+
import { ChevronRightIcon } from "../Icons/ChevronRightIcon";
|
|
5
|
+
import { ChevronDownIcon } from "../Icons/ChevronDownIcon";
|
|
6
|
+
import Text from "../Text/Text";
|
|
7
|
+
|
|
8
|
+
export interface AccordionItemProps {
|
|
9
|
+
id: string;
|
|
10
|
+
title: string;
|
|
11
|
+
content: React.ReactNode;
|
|
12
|
+
className?: string;
|
|
13
|
+
isCollapsedByDefault?: boolean;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const AccordionItem: React.VFC<AccordionItemProps> = ({
|
|
17
|
+
id,
|
|
18
|
+
title,
|
|
19
|
+
content,
|
|
20
|
+
isCollapsedByDefault = false,
|
|
21
|
+
}) => {
|
|
22
|
+
const [isCollapsed, toggleIsCollapsed] = useReducer(
|
|
23
|
+
(state) => !state,
|
|
24
|
+
isCollapsedByDefault
|
|
25
|
+
);
|
|
26
|
+
const Chevron = isCollapsed ? ChevronRightIcon : ChevronDownIcon;
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<li
|
|
30
|
+
className={"bg-white border-b last:border-b-0 border-slate-100"}
|
|
31
|
+
data-test-id={id}
|
|
32
|
+
>
|
|
33
|
+
<div
|
|
34
|
+
onClick={toggleIsCollapsed}
|
|
35
|
+
className={classNames(
|
|
36
|
+
"p-4 w-full flex flex-row space-x-4 select-none",
|
|
37
|
+
"cursor-pointer hover:bg-blue-50 transition-colors ease-in-out duration-300",
|
|
38
|
+
{
|
|
39
|
+
"border-b border-slate-100": !isCollapsed,
|
|
40
|
+
}
|
|
41
|
+
)}
|
|
42
|
+
>
|
|
43
|
+
<Chevron className={"text-slate-300"} />
|
|
44
|
+
<Text text={title} type={"lg-strong"} />
|
|
45
|
+
</div>
|
|
46
|
+
|
|
47
|
+
<div className={classNames({ hidden: isCollapsed })}>{content}</div>
|
|
48
|
+
</li>
|
|
49
|
+
);
|
|
50
|
+
};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Control, useForm } from "react-hook-form";
|
|
3
|
+
|
|
4
|
+
import { PrimaryButton } from "../ButtonV2/PrimaryButton";
|
|
5
|
+
import { InputProps } from "../Input/Input";
|
|
6
|
+
import { RadioGroupProps } from "../RadioGroup/RadioGroupV2";
|
|
7
|
+
import { SelectProps } from "../Select/SelectV2";
|
|
8
|
+
|
|
9
|
+
import { FormInput } from "./FormInput";
|
|
10
|
+
import { FormFieldProps, FormFieldRowProps, FormProps } from "./form.types";
|
|
11
|
+
import { isRequired } from "./form.transformer";
|
|
12
|
+
import { FormRadioGroup } from "./FormRadioGroup";
|
|
13
|
+
import { FormSelect } from "./FormSelect";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Create a straight forward Form.
|
|
17
|
+
*
|
|
18
|
+
* TODO: wrap this in some Page component to style the div and buttons
|
|
19
|
+
* WARNING: don't use this component before some styling errors are resolved.
|
|
20
|
+
*/
|
|
21
|
+
export function Form<TFieldValues>({
|
|
22
|
+
fields,
|
|
23
|
+
onValid,
|
|
24
|
+
onError,
|
|
25
|
+
defaultValues,
|
|
26
|
+
}: FormProps<TFieldValues>): JSX.Element {
|
|
27
|
+
const {
|
|
28
|
+
register,
|
|
29
|
+
handleSubmit,
|
|
30
|
+
control,
|
|
31
|
+
formState: { errors },
|
|
32
|
+
} = useForm<TFieldValues>({
|
|
33
|
+
criteriaMode: "all",
|
|
34
|
+
defaultValues: defaultValues,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const fieldMapper = ({
|
|
38
|
+
type,
|
|
39
|
+
name,
|
|
40
|
+
options,
|
|
41
|
+
fieldProps = {},
|
|
42
|
+
...decoratorProps
|
|
43
|
+
}: FormFieldProps<TFieldValues>) => {
|
|
44
|
+
switch (type) {
|
|
45
|
+
case "text":
|
|
46
|
+
case "number":
|
|
47
|
+
case "email":
|
|
48
|
+
case "password":
|
|
49
|
+
return (
|
|
50
|
+
<FormInput
|
|
51
|
+
key={name}
|
|
52
|
+
{...decoratorProps}
|
|
53
|
+
fieldRequired={isRequired(options)}
|
|
54
|
+
fieldErrors={errors}
|
|
55
|
+
{...(fieldProps as InputProps)}
|
|
56
|
+
{...register(name, options)}
|
|
57
|
+
type={type || "text"}
|
|
58
|
+
/>
|
|
59
|
+
);
|
|
60
|
+
case "select":
|
|
61
|
+
return (
|
|
62
|
+
<FormSelect
|
|
63
|
+
key={name}
|
|
64
|
+
{...decoratorProps}
|
|
65
|
+
fieldRequired={isRequired(options)}
|
|
66
|
+
fieldErrors={errors}
|
|
67
|
+
{...(fieldProps as SelectProps)}
|
|
68
|
+
control={control as Control}
|
|
69
|
+
rules={options}
|
|
70
|
+
name={name}
|
|
71
|
+
/>
|
|
72
|
+
);
|
|
73
|
+
case "radioGroup":
|
|
74
|
+
return (
|
|
75
|
+
<FormRadioGroup
|
|
76
|
+
key={name}
|
|
77
|
+
{...decoratorProps}
|
|
78
|
+
fieldRequired={isRequired(options)}
|
|
79
|
+
fieldErrors={errors}
|
|
80
|
+
{...(fieldProps as RadioGroupProps)}
|
|
81
|
+
{...register(name, options)}
|
|
82
|
+
/>
|
|
83
|
+
);
|
|
84
|
+
default:
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
return (
|
|
90
|
+
<div className="space-y-4">
|
|
91
|
+
{fields.map((props) => {
|
|
92
|
+
if (props.type === "row") {
|
|
93
|
+
const { fields: rowFields, key } =
|
|
94
|
+
props as FormFieldRowProps<TFieldValues>;
|
|
95
|
+
return (
|
|
96
|
+
<div className={"flex flex-row"} key={key}>
|
|
97
|
+
{rowFields.map(fieldMapper)}
|
|
98
|
+
</div>
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
return fieldMapper(props);
|
|
102
|
+
})}
|
|
103
|
+
<PrimaryButton onClick={handleSubmit(onValid, onError)} text={"submit"} />
|
|
104
|
+
</div>
|
|
105
|
+
);
|
|
106
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { ErrorMessage } from "@hookform/error-message";
|
|
3
|
+
import classNames from "classnames";
|
|
4
|
+
|
|
5
|
+
import { Text } from "../Text/Text";
|
|
6
|
+
|
|
7
|
+
import { FormFieldDecoratorWithGeneratedProps } from "./form.types";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Decorator for any input component. Adds a label and additional information to be shown.
|
|
11
|
+
*
|
|
12
|
+
* Includes the default error handling from react-hook-form.
|
|
13
|
+
*/
|
|
14
|
+
export function FormFieldDecorator({
|
|
15
|
+
name,
|
|
16
|
+
children,
|
|
17
|
+
label,
|
|
18
|
+
fieldRequired,
|
|
19
|
+
info,
|
|
20
|
+
fieldErrors,
|
|
21
|
+
decoratorClassname,
|
|
22
|
+
}: FormFieldDecoratorWithGeneratedProps): JSX.Element {
|
|
23
|
+
return (
|
|
24
|
+
<div className={classNames(decoratorClassname)}>
|
|
25
|
+
{label && (
|
|
26
|
+
<label
|
|
27
|
+
className="cweb-form-field-label block mb-1"
|
|
28
|
+
htmlFor={name}
|
|
29
|
+
data-is-required={fieldRequired}
|
|
30
|
+
>
|
|
31
|
+
<Text
|
|
32
|
+
className="cweb-form-field-label-text"
|
|
33
|
+
inline={true}
|
|
34
|
+
text={label}
|
|
35
|
+
/>
|
|
36
|
+
</label>
|
|
37
|
+
)}
|
|
38
|
+
|
|
39
|
+
<fieldset className="cweb-form-fieldset">{children}</fieldset>
|
|
40
|
+
{info && (
|
|
41
|
+
<Text
|
|
42
|
+
className="mt-1 cweb-form-info-text"
|
|
43
|
+
type="sm"
|
|
44
|
+
color="slate-500"
|
|
45
|
+
text={info}
|
|
46
|
+
/>
|
|
47
|
+
)}
|
|
48
|
+
|
|
49
|
+
<ErrorMessage
|
|
50
|
+
errors={fieldErrors}
|
|
51
|
+
name={name}
|
|
52
|
+
render={({ messages }) =>
|
|
53
|
+
messages &&
|
|
54
|
+
Object.entries(messages).map(([key, message]) => (
|
|
55
|
+
<Text
|
|
56
|
+
key={key}
|
|
57
|
+
className="mt-1"
|
|
58
|
+
text={message as string}
|
|
59
|
+
color={"red"}
|
|
60
|
+
/>
|
|
61
|
+
))
|
|
62
|
+
}
|
|
63
|
+
/>
|
|
64
|
+
</div>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
import Input from "../Input/Input";
|
|
4
|
+
|
|
5
|
+
import { FormFieldDecorator } from "./FormFieldDecorator";
|
|
6
|
+
import { hasError } from "./form.transformer";
|
|
7
|
+
import { FormInputProps } from "./form.types";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Input field that can be used in any react-hook-form context.
|
|
11
|
+
*/
|
|
12
|
+
const FormInputInner = React.forwardRef<HTMLInputElement, FormInputProps>(
|
|
13
|
+
(
|
|
14
|
+
{
|
|
15
|
+
name,
|
|
16
|
+
fieldErrors,
|
|
17
|
+
fieldRequired,
|
|
18
|
+
label,
|
|
19
|
+
info,
|
|
20
|
+
decoratorClassname,
|
|
21
|
+
...fieldProps
|
|
22
|
+
},
|
|
23
|
+
ref
|
|
24
|
+
) => {
|
|
25
|
+
return (
|
|
26
|
+
<FormFieldDecorator
|
|
27
|
+
name={name}
|
|
28
|
+
fieldErrors={fieldErrors}
|
|
29
|
+
fieldRequired={fieldRequired}
|
|
30
|
+
label={label}
|
|
31
|
+
info={info}
|
|
32
|
+
decoratorClassname={decoratorClassname}
|
|
33
|
+
>
|
|
34
|
+
<Input
|
|
35
|
+
{...fieldProps}
|
|
36
|
+
isError={hasError(name, fieldErrors)}
|
|
37
|
+
ref={ref}
|
|
38
|
+
name={name}
|
|
39
|
+
/>
|
|
40
|
+
</FormFieldDecorator>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
export const FormInput = React.forwardRef<HTMLInputElement, FormInputProps>(
|
|
46
|
+
(props, ref) => <FormInputInner {...props} ref={ref} />
|
|
47
|
+
);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
import { RadioGroupV2 } from "../RadioGroup/RadioGroupV2";
|
|
4
|
+
|
|
5
|
+
import { FormFieldDecorator } from "./FormFieldDecorator";
|
|
6
|
+
import { hasError } from "./form.transformer";
|
|
7
|
+
import { FormRadioGroupProps } from "./form.types";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Input field that can be used in any react-hook-form context.
|
|
11
|
+
*/
|
|
12
|
+
function FormRadioGroupInner(
|
|
13
|
+
{ innerRef, name, fieldErrors, fieldRequired, label, info, decoratorClassname, ...fieldProps }: FormRadioGroupProps): JSX.Element {
|
|
14
|
+
return (
|
|
15
|
+
<FormFieldDecorator name={name} fieldErrors={fieldErrors} fieldRequired={fieldRequired} label={label} info={info} decoratorClassname={decoratorClassname}>
|
|
16
|
+
<RadioGroupV2 {...fieldProps} isError={hasError(name, fieldErrors)} ref={innerRef} name={name} />
|
|
17
|
+
</FormFieldDecorator>
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const FormRadioGroup = React.forwardRef<HTMLInputElement, FormRadioGroupProps>((props, ref) => (
|
|
22
|
+
<FormRadioGroupInner {...props} innerRef={ref} />
|
|
23
|
+
));
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Controller } from "react-hook-form";
|
|
3
|
+
|
|
4
|
+
import { Select } from "../Select/SelectV2";
|
|
5
|
+
|
|
6
|
+
import { FormSelectProps } from "./form.types";
|
|
7
|
+
import { FormFieldDecorator } from "./FormFieldDecorator";
|
|
8
|
+
import { hasError } from "./form.transformer";
|
|
9
|
+
|
|
10
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
11
|
+
export const FormSelect = React.forwardRef<any, FormSelectProps>((
|
|
12
|
+
{
|
|
13
|
+
control, name, rules, fieldErrors, fieldRequired, label, info, decoratorClassname,
|
|
14
|
+
...selectProps
|
|
15
|
+
}, innerRef) => {
|
|
16
|
+
return (
|
|
17
|
+
<FormFieldDecorator name={name} fieldErrors={fieldErrors} fieldRequired={fieldRequired} label={label} info={info} decoratorClassname={decoratorClassname}>
|
|
18
|
+
<Controller
|
|
19
|
+
name={name}
|
|
20
|
+
control={control}
|
|
21
|
+
rules={rules}
|
|
22
|
+
render={({ field }) => (
|
|
23
|
+
<Select
|
|
24
|
+
{...selectProps}
|
|
25
|
+
{...field}
|
|
26
|
+
isError={hasError(name, fieldErrors)}
|
|
27
|
+
ref={innerRef}
|
|
28
|
+
/>)}
|
|
29
|
+
/>
|
|
30
|
+
</FormFieldDecorator>
|
|
31
|
+
);
|
|
32
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { FieldErrors, RegisterOptions } from "react-hook-form";
|
|
2
|
+
|
|
3
|
+
export const hasError = (name?: string, errors?: FieldErrors): boolean => {
|
|
4
|
+
return !!(name && errors && name in errors);
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export const isRequired = (options?: RegisterOptions): boolean => {
|
|
8
|
+
return !!(options && "required" in options);
|
|
9
|
+
};
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Control,
|
|
3
|
+
DeepPartial,
|
|
4
|
+
FieldErrors,
|
|
5
|
+
FieldPath,
|
|
6
|
+
FieldValues,
|
|
7
|
+
RegisterOptions,
|
|
8
|
+
SubmitErrorHandler,
|
|
9
|
+
SubmitHandler,
|
|
10
|
+
} from "react-hook-form";
|
|
11
|
+
import React, { HTMLInputTypeAttribute } from "react";
|
|
12
|
+
|
|
13
|
+
import { InputProps } from "../Input/Input";
|
|
14
|
+
import { RadioGroupProps } from "../RadioGroup/RadioGroupV2";
|
|
15
|
+
import { SelectProps } from "../Select/SelectV2";
|
|
16
|
+
|
|
17
|
+
export type AllowedTextInputTypes = Extract<
|
|
18
|
+
HTMLInputTypeAttribute,
|
|
19
|
+
"email" | "number" | "password" | "text"
|
|
20
|
+
>;
|
|
21
|
+
|
|
22
|
+
// --------------------------------------------
|
|
23
|
+
// The namespaces for props and components are structured as:
|
|
24
|
+
// <<type>>Props : usable in any context
|
|
25
|
+
// Form<<type>>Props : usable in any react-hook-form context
|
|
26
|
+
// FormField<<type>>Props: usable in specifically the Form component
|
|
27
|
+
// --------------------------------------------
|
|
28
|
+
|
|
29
|
+
// the input for the 'out-of-the-box' Form
|
|
30
|
+
export interface FormProps<TFieldValues extends FieldValues> {
|
|
31
|
+
// the fields to be rendered
|
|
32
|
+
fields: (FormFieldProps<TFieldValues> | FormFieldRowProps<TFieldValues>)[];
|
|
33
|
+
onValid: SubmitHandler<TFieldValues>;
|
|
34
|
+
onError?: SubmitErrorHandler<TFieldValues>;
|
|
35
|
+
// inject the form with already known data (for instance, when updating
|
|
36
|
+
defaultValues?: DeepPartial<TFieldValues>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
interface FormFieldGenericProps<TFieldType, TFieldValues>
|
|
40
|
+
extends FormFieldDecoratorProps {
|
|
41
|
+
// the name of the field, which is registered within react-hook-form
|
|
42
|
+
name: FieldPath<TFieldValues>;
|
|
43
|
+
// the options registered within react-hook-form
|
|
44
|
+
options?: RegisterOptions;
|
|
45
|
+
// any additional props to customise the component that renders the field
|
|
46
|
+
fieldProps?: TFieldType;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// these are the configuration options for the decorator
|
|
50
|
+
interface FormFieldDecoratorProps {
|
|
51
|
+
// the label shown to the user within the decorator
|
|
52
|
+
label?: string;
|
|
53
|
+
// the additional information shown to the user within the decorator
|
|
54
|
+
info?: string;
|
|
55
|
+
// allow for custom styling of the decorator component
|
|
56
|
+
decoratorClassname?: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// these are all the types that can be included in the 'out-of-the-box' Form
|
|
60
|
+
export type FormFieldProps<TFieldValues> =
|
|
61
|
+
| FormFieldInputProps<TFieldValues>
|
|
62
|
+
| FormFieldSelectProps<TFieldValues>
|
|
63
|
+
| FormFieldRadioGroupProps<TFieldValues>;
|
|
64
|
+
|
|
65
|
+
// allow a row of fields
|
|
66
|
+
export interface FormFieldRowProps<TFieldValues> {
|
|
67
|
+
type: "row";
|
|
68
|
+
// add a unique key string to ensure react can render the map in an optimized manner
|
|
69
|
+
key: string;
|
|
70
|
+
fields: FormFieldProps<TFieldValues>[];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
interface FormFieldInputProps<TFieldValues>
|
|
74
|
+
extends FormFieldGenericProps<Omit<InputProps, "name">, TFieldValues> {
|
|
75
|
+
// the type of component rendered to display the field
|
|
76
|
+
type: AllowedTextInputTypes;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
interface FormFieldRadioGroupProps<TFieldValues>
|
|
80
|
+
extends FormFieldGenericProps<Omit<RadioGroupProps, "name">, TFieldValues> {
|
|
81
|
+
type: "radioGroup";
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface FormFieldSelectProps<TFieldValues>
|
|
85
|
+
extends FormFieldGenericProps<SelectProps, TFieldValues> {
|
|
86
|
+
type: "select";
|
|
87
|
+
// this makes it now required, because we need the options in there
|
|
88
|
+
fieldProps: SelectProps;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// --------------------------------------------
|
|
92
|
+
// The types below are used for components that are used in a react-hook-form context but not the Form context
|
|
93
|
+
// --------------------------------------------
|
|
94
|
+
|
|
95
|
+
// these are the inputs required to decorate fields
|
|
96
|
+
// they are generated within the Form component, but could also be manually inserted
|
|
97
|
+
export interface FormFieldDecoratorWithGeneratedProps
|
|
98
|
+
extends FormFieldDecoratorProps {
|
|
99
|
+
// coming from register react-hook-form
|
|
100
|
+
name: string;
|
|
101
|
+
// coming from useForms formState react-hook-form
|
|
102
|
+
fieldErrors: FieldErrors;
|
|
103
|
+
// automatically generated within Form from the RegisterOptions
|
|
104
|
+
// showing an asterisk to the label if true
|
|
105
|
+
fieldRequired: boolean;
|
|
106
|
+
// the field that is decorated
|
|
107
|
+
children?: React.ReactNode;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export interface FormInputProps
|
|
111
|
+
extends Omit<InputProps, "name">,
|
|
112
|
+
FormFieldDecoratorWithGeneratedProps {
|
|
113
|
+
type: Extract<
|
|
114
|
+
HTMLInputTypeAttribute,
|
|
115
|
+
"email" | "number" | "password" | "text"
|
|
116
|
+
>;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export interface FormRadioGroupProps
|
|
120
|
+
extends RadioGroupProps,
|
|
121
|
+
FormFieldDecoratorWithGeneratedProps {}
|
|
122
|
+
|
|
123
|
+
export interface FormSelectProps
|
|
124
|
+
extends Omit<SelectProps, "name">,
|
|
125
|
+
FormFieldDecoratorWithGeneratedProps {
|
|
126
|
+
control: Control;
|
|
127
|
+
// ref: https://react-hook-form.com/ts#UseControllerProps
|
|
128
|
+
rules?: Exclude<
|
|
129
|
+
RegisterOptions,
|
|
130
|
+
"valueAsNumber" | "valueAsDate" | "setValueAs"
|
|
131
|
+
>;
|
|
132
|
+
}
|