-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathFormGroupLayout.tsx
More file actions
98 lines (88 loc) · 3.5 KB
/
FormGroupLayout.tsx
File metadata and controls
98 lines (88 loc) · 3.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
/* eslint-disable complexity */
import { PropsWithChildren, ReactNode, CSSProperties, useMemo } from "react";
import { FieldError, FieldValues, get } from "react-hook-form";
import { FormGroup, FormFeedback, FormText, InputGroup } from "reactstrap";
import { useSafeNameId } from "src/lib/hooks/useSafeNameId";
import { CommonInputProps, MergedAddonProps } from "./types/CommonInputProps";
import "./styles/FormGroupLayout.css";
import { FormGroupLayoutLabel } from "./FormGroupLayoutLabel";
import { UnknownType, useFormContextInternal } from "./context/FormContext";
type FormGroupLayoutProps<T extends FieldValues = UnknownType, TRenderAddon = unknown> = PropsWithChildren<
Pick<CommonInputProps<T>, "helpText" | "label" | "name" | "id" | "labelToolTip" | "inputOnly" | "hideValidationMessage">
> & {
layout?: "checkbox" | "switch";
addonLeft?: ReactNode | ((props: TRenderAddon) => ReactNode);
addonRight?: ReactNode | ((props: TRenderAddon) => ReactNode);
addonProps?: MergedAddonProps<TRenderAddon>;
inputGroupStyle?: CSSProperties;
formGroupId?: string;
};
const FormGroupLayout = <T extends FieldValues = UnknownType, TRenderAddon = unknown>(props: FormGroupLayoutProps<T, TRenderAddon>) => {
const {
label,
helpText,
children,
layout,
labelToolTip,
inputOnly,
addonLeft,
addonRight,
inputGroupStyle,
formGroupId,
addonProps,
hideValidationMessage = false,
} = props;
const { name, id } = useSafeNameId(props?.name ?? "", props.id);
const { formState, hideValidationMessages = false } = useFormContextInternal() ?? {};
const fieldError = formState ? (get(formState.errors, name) as FieldError | undefined) : undefined;
const errorMessage = String(fieldError?.message);
const switchLayout = layout === "switch";
const checkboxLayout = layout === "checkbox";
if (inputOnly && (switchLayout || checkboxLayout)) {
throw "'inputOnly' is not possible with switches or checkboxes";
}
const effectiveAddonLeft = useMemo(
() =>
addonLeft instanceof Function && addonProps
? (addonLeft as (props: TRenderAddon) => ReactNode)(addonProps)
: (addonLeft as ReactNode),
[addonLeft, addonProps],
);
const effectiveAddonRight = useMemo(
() =>
addonRight instanceof Function && addonProps
? (addonRight as (props: TRenderAddon) => ReactNode)(addonProps)
: (addonRight as ReactNode),
[addonRight, addonProps],
);
const hideErrorMessage = useMemo(() => hideValidationMessages || hideValidationMessage, [hideValidationMessages, hideValidationMessage]);
return inputOnly ? (
<>
{children}
{!hideErrorMessage && <FormFeedback>{errorMessage}</FormFeedback>}
</>
) : (
<FormGroup id={formGroupId} switch={switchLayout ? true : undefined} check={checkboxLayout ? true : undefined}>
<FormGroupLayoutLabel<T> label={label} fieldName={props.name} fieldId={id} tooltip={labelToolTip} layout={layout} />
{switchLayout || checkboxLayout ? (
children
) : (
<InputGroup
style={{
flexWrap: "nowrap",
alignItems: "center",
...inputGroupStyle,
}}
className={fieldError ? "is-invalid" : undefined}
>
{effectiveAddonLeft}
{children}
{effectiveAddonRight}
</InputGroup>
)}
{!hideErrorMessage && <FormFeedback>{errorMessage}</FormFeedback>}
{helpText && <FormText>{helpText}</FormText>}
</FormGroup>
);
};
export { FormGroupLayout, FormGroupLayoutProps };