2022-03-21 11:09:01 -07:00
|
|
|
import React, { useMemo } from 'react';
|
|
|
|
import { v4 as uuidv4 } from 'uuid';
|
|
|
|
|
2022-05-09 06:52:41 -07:00
|
|
|
import Checkbox from '../checkbox/checkbox';
|
|
|
|
import HStack from '../hstack/hstack';
|
|
|
|
import Stack from '../stack/stack';
|
|
|
|
|
2022-03-21 11:09:01 -07:00
|
|
|
interface IFormGroup {
|
2022-04-30 21:39:58 -07:00
|
|
|
/** Input label message. */
|
2023-02-15 13:26:27 -08:00
|
|
|
labelText?: React.ReactNode
|
2022-06-07 11:55:34 -07:00
|
|
|
/** Input label tooltip message. */
|
2023-02-15 13:26:27 -08:00
|
|
|
labelTitle?: string
|
2022-04-30 21:39:58 -07:00
|
|
|
/** Input hint message. */
|
2023-02-15 13:26:27 -08:00
|
|
|
hintText?: React.ReactNode
|
2022-04-30 21:39:58 -07:00
|
|
|
/** Input errors. */
|
2022-03-21 11:09:01 -07:00
|
|
|
errors?: string[]
|
2023-01-10 15:03:15 -08:00
|
|
|
/** Elements to display within the FormGroup. */
|
|
|
|
children: React.ReactNode
|
2022-03-21 11:09:01 -07:00
|
|
|
}
|
|
|
|
|
2022-05-06 16:51:06 -07:00
|
|
|
/** Input container with label. Renders the child. */
|
2022-03-21 11:09:01 -07:00
|
|
|
const FormGroup: React.FC<IFormGroup> = (props) => {
|
2022-06-07 11:55:34 -07:00
|
|
|
const { children, errors = [], labelText, labelTitle, hintText } = props;
|
2022-03-21 11:09:01 -07:00
|
|
|
const formFieldId: string = useMemo(() => `field-${uuidv4()}`, []);
|
|
|
|
const inputChildren = React.Children.toArray(children);
|
2022-05-09 09:53:16 -07:00
|
|
|
const hasError = errors?.length > 0;
|
2022-03-21 11:09:01 -07:00
|
|
|
|
|
|
|
let firstChild;
|
|
|
|
if (React.isValidElement(inputChildren[0])) {
|
|
|
|
firstChild = React.cloneElement(
|
|
|
|
inputChildren[0],
|
2023-06-13 14:25:39 -07:00
|
|
|
// @ts-ignore
|
2023-01-10 10:41:32 -08:00
|
|
|
{ id: formFieldId },
|
2022-03-21 11:09:01 -07:00
|
|
|
);
|
|
|
|
}
|
2023-06-13 14:25:39 -07:00
|
|
|
|
|
|
|
// @ts-ignore
|
2022-05-09 06:52:41 -07:00
|
|
|
const isCheckboxFormGroup = firstChild?.type === Checkbox;
|
|
|
|
|
|
|
|
if (isCheckboxFormGroup) {
|
|
|
|
return (
|
|
|
|
<HStack alignItems='start' space={2}>
|
|
|
|
{firstChild}
|
|
|
|
|
|
|
|
<Stack>
|
|
|
|
{labelText && (
|
|
|
|
<label
|
|
|
|
htmlFor={formFieldId}
|
|
|
|
data-testid='form-group-label'
|
2022-07-22 10:30:16 -07:00
|
|
|
className='-mt-0.5 block text-sm font-medium text-gray-900 dark:text-gray-100'
|
2022-06-07 11:55:34 -07:00
|
|
|
title={labelTitle}
|
2022-05-09 06:52:41 -07:00
|
|
|
>
|
|
|
|
{labelText}
|
|
|
|
</label>
|
|
|
|
)}
|
|
|
|
|
2022-05-09 10:19:49 -07:00
|
|
|
{hasError && (
|
2022-05-09 06:52:41 -07:00
|
|
|
<div>
|
|
|
|
<p
|
|
|
|
data-testid='form-group-error'
|
2023-02-01 14:13:42 -08:00
|
|
|
className='form-error relative mt-0.5 inline-block rounded-md bg-danger-200 px-2 py-1 text-xs text-danger-900'
|
2022-05-09 06:52:41 -07:00
|
|
|
>
|
|
|
|
{errors.join(', ')}
|
|
|
|
</p>
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
|
|
|
|
{hintText && (
|
2022-07-22 10:30:16 -07:00
|
|
|
<p data-testid='form-group-hint' className='mt-0.5 text-xs text-gray-700 dark:text-gray-600'>
|
2022-05-09 06:52:41 -07:00
|
|
|
{hintText}
|
|
|
|
</p>
|
|
|
|
)}
|
|
|
|
</Stack>
|
|
|
|
</HStack>
|
|
|
|
);
|
|
|
|
}
|
2022-03-21 11:09:01 -07:00
|
|
|
|
|
|
|
return (
|
|
|
|
<div>
|
2022-05-05 15:45:32 -07:00
|
|
|
{labelText && (
|
|
|
|
<label
|
|
|
|
htmlFor={formFieldId}
|
|
|
|
data-testid='form-group-label'
|
2022-07-22 10:30:16 -07:00
|
|
|
className='block text-sm font-medium text-gray-900 dark:text-gray-100'
|
2022-06-07 11:55:34 -07:00
|
|
|
title={labelTitle}
|
2022-05-05 15:45:32 -07:00
|
|
|
>
|
|
|
|
{labelText}
|
|
|
|
</label>
|
|
|
|
)}
|
2022-03-21 11:09:01 -07:00
|
|
|
|
2022-03-29 06:40:02 -07:00
|
|
|
<div className='mt-1 dark:text-white'>
|
2023-03-29 18:42:57 -07:00
|
|
|
{hintText && (
|
|
|
|
<p data-testid='form-group-hint' className='mb-0.5 text-xs text-gray-700 dark:text-gray-600'>
|
|
|
|
{hintText}
|
|
|
|
</p>
|
|
|
|
)}
|
|
|
|
|
2022-03-21 11:09:01 -07:00
|
|
|
{firstChild}
|
|
|
|
{inputChildren.filter((_, i) => i !== 0)}
|
|
|
|
|
2022-05-09 09:53:16 -07:00
|
|
|
{hasError && (
|
2022-04-04 08:53:47 -07:00
|
|
|
<p
|
|
|
|
data-testid='form-group-error'
|
2023-02-01 14:13:42 -08:00
|
|
|
className='form-error relative mt-0.5 inline-block rounded-md bg-danger-200 px-2 py-1 text-xs text-danger-900'
|
2022-04-04 08:53:47 -07:00
|
|
|
>
|
2022-03-21 11:09:01 -07:00
|
|
|
{errors.join(', ')}
|
|
|
|
</p>
|
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
export default FormGroup;
|