@availity/mui-controlled-form 0.2.5 → 0.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.
Files changed (46) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +2 -2
  3. package/dist/index.d.mts +122 -34
  4. package/dist/index.d.ts +122 -34
  5. package/dist/index.js +263 -225
  6. package/dist/index.mjs +279 -240
  7. package/package.json +2 -2
  8. package/src/index.ts +47 -0
  9. package/src/lib/AsyncAutocomplete.stories.tsx +21 -36
  10. package/src/lib/AsyncAutocomplete.test.tsx +17 -53
  11. package/src/lib/AsyncAutocomplete.tsx +23 -20
  12. package/src/lib/Autocomplete.stories.tsx +20 -33
  13. package/src/lib/Autocomplete.test.tsx +7 -37
  14. package/src/lib/Autocomplete.tsx +16 -15
  15. package/src/lib/Checkbox.stories.tsx +50 -43
  16. package/src/lib/Checkbox.test.tsx +14 -46
  17. package/src/lib/Checkbox.tsx +30 -15
  18. package/src/lib/CodesAutocomplete.stories.tsx +21 -35
  19. package/src/lib/CodesAutocomplete.test.tsx +20 -54
  20. package/src/lib/CodesAutocomplete.tsx +23 -20
  21. package/src/lib/ControlledForm.stories.tsx +1 -0
  22. package/src/lib/ControlledForm.tsx +8 -4
  23. package/src/lib/Datepicker.stories.tsx +19 -32
  24. package/src/lib/Datepicker.test.tsx +3 -35
  25. package/src/lib/Datepicker.tsx +18 -10
  26. package/src/lib/Input.stories.tsx +32 -33
  27. package/src/lib/Input.test.tsx +71 -7
  28. package/src/lib/Input.tsx +44 -24
  29. package/src/lib/OrganizationAutocomplete.stories.tsx +30 -35
  30. package/src/lib/OrganizationAutocomplete.test.tsx +23 -57
  31. package/src/lib/OrganizationAutocomplete.tsx +24 -23
  32. package/src/lib/ProviderAutocomplete.stories.tsx +20 -35
  33. package/src/lib/ProviderAutocomplete.test.tsx +29 -63
  34. package/src/lib/ProviderAutocomplete.tsx +22 -20
  35. package/src/lib/RadioGroup.stories.tsx +41 -36
  36. package/src/lib/RadioGroup.test.tsx +3 -35
  37. package/src/lib/RadioGroup.tsx +33 -25
  38. package/src/lib/Select.stories.tsx +78 -45
  39. package/src/lib/Select.test.tsx +8 -36
  40. package/src/lib/Select.tsx +44 -25
  41. package/src/lib/TextField.stories.tsx +26 -34
  42. package/src/lib/TextField.test.tsx +71 -5
  43. package/src/lib/TextField.tsx +55 -37
  44. package/src/lib/Types.tsx +2489 -0
  45. package/src/lib/UtilComponents.tsx +52 -0
  46. package/docs/propDefinitions.tsx +0 -31
@@ -1,64 +1,71 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react';
2
- import { ControlledCheckbox } from './Checkbox';
3
- import { ControlledForm } from './ControlledForm';
2
+ import { ControlledCheckbox, ControlledCheckboxProps } from './Checkbox';
4
3
  import { Button } from '@availity/mui-button';
5
- import { useFormContext } from 'react-hook-form';
4
+ import { FormProvider, useForm } from 'react-hook-form';
6
5
  import { Paper } from '@availity/mui-paper';
7
6
  import { Typography } from '@availity/mui-typography';
8
7
  import { FormControlLabel, FormGroup, FormControl, FormLabel } from '@availity/mui-form-utils';
9
8
  import { Grid } from '@availity/mui-layout';
9
+ import { AllControllerPropertiesCategorized, CheckboxPropsCategorized } from './Types';
10
10
 
11
11
  const meta: Meta<typeof ControlledCheckbox> = {
12
12
  title: 'Form Components/Controlled Form/ControlledCheckbox',
13
13
  component: ControlledCheckbox,
14
14
  tags: ['autodocs'],
15
+ argTypes: {...AllControllerPropertiesCategorized, ...CheckboxPropsCategorized},
16
+ parameters: {
17
+ controls: {
18
+ exclude: [
19
+ 'form',
20
+ 'formAction',
21
+ 'formEncType',
22
+ 'formMethod',
23
+ 'formNoValidate',
24
+ 'formTarget',
25
+ 'key',
26
+ 'max',
27
+ 'maxLength',
28
+ 'min',
29
+ 'minLength',
30
+ 'pattern',
31
+ 'style',
32
+ 'tabIndex'
33
+ ]
34
+ }
35
+ }
15
36
  };
16
37
 
17
38
  export default meta;
18
39
 
19
40
  export const _ControlledCheckbox: StoryObj<typeof ControlledCheckbox> = {
20
- render: () => {
21
- const SubmittedValues = () => {
22
- const {
23
- getValues,
24
- formState: { isSubmitSuccessful },
25
- } = useFormContext();
41
+ render: (args: ControlledCheckboxProps) => {
42
+ const methods = useForm();
26
43
 
27
- return isSubmitSuccessful ? (
28
- <Paper sx={{ padding: '1.5rem', marginTop: '1.5rem' }}>
29
- <Typography variant="h2">Submitted Values</Typography>
30
- <pre>{JSON.stringify(getValues(), null, 2)}</pre>
31
- </Paper>
32
- ) : null;
33
- };
34
-
35
- const Actions = () => {
36
- const {
37
- reset,
38
- formState: { isSubmitSuccessful },
39
- } = useFormContext();
40
- return (
41
- <Grid container direction="row" justifyContent="space-between" marginTop={1}>
42
- <Button disabled={!isSubmitSuccessful} children="Reset" color="secondary" onClick={() => reset()} />
43
- <Button type="submit" disabled={isSubmitSuccessful} children="Submit" />
44
- </Grid>
45
- );
46
- };
47
44
  return (
48
- <ControlledForm onSubmit={(data) => data} values={{ controlledCheckbox: undefined }}>
49
- <FormControl>
50
- <FormLabel id="radio-group" component="div">
51
- Radio Group
52
- </FormLabel>
53
- <FormGroup>
54
- <FormControlLabel label="Option 1" control={<ControlledCheckbox name="Option 1" />} />
55
- <FormControlLabel label="Option 2" control={<ControlledCheckbox name="Option 2" />} />
56
- <FormControlLabel label="Option 3" control={<ControlledCheckbox name="Option 3" />} />
57
- </FormGroup>
58
- </FormControl>
59
- <Actions />
60
- <SubmittedValues />
61
- </ControlledForm>
45
+ <FormProvider {...methods}>
46
+ <form onSubmit={methods.handleSubmit((data) => data)}>
47
+ <FormControl>
48
+ <FormLabel id="radio-group" component="div">
49
+ Radio Group
50
+ </FormLabel>
51
+ <FormGroup>
52
+ <FormControlLabel label="Option 1" control={<ControlledCheckbox {...args} />} />
53
+ <FormControlLabel label="Option 2" control={<ControlledCheckbox name="Option 2" />} />
54
+ <FormControlLabel label="Option 3" control={<ControlledCheckbox name="Option 3" />} />
55
+ </FormGroup>
56
+ </FormControl>
57
+ <Grid container direction="row" justifyContent="space-between" marginTop={1}>
58
+ <Button disabled={!methods?.formState?.isSubmitSuccessful} children="Reset" color="secondary" onClick={() => methods.reset()} />
59
+ <Button type="submit" disabled={methods?.formState?.isSubmitSuccessful} children="Submit" />
60
+ </Grid>
61
+ { methods?.formState?.isSubmitSuccessful ? (
62
+ <Paper sx={{ padding: '1.5rem', marginTop: '1.5rem' }}>
63
+ <Typography variant="h2">Submitted Values</Typography>
64
+ <pre data-testid="result">{JSON.stringify(methods.getValues(), null, 2)}</pre>
65
+ </Paper>
66
+ ) : null }
67
+ </form>
68
+ </FormProvider>
62
69
  );
63
70
  },
64
71
  args: {
@@ -1,57 +1,25 @@
1
1
  import { render, fireEvent, waitFor } from '@testing-library/react';
2
2
  import { FormControl, FormLabel, FormControlLabel, FormGroup } from '@availity/mui-form-utils';
3
- import { useFormContext } from 'react-hook-form';
4
- import { Paper } from '@availity/mui-paper';
5
- import { Typography } from '@availity/mui-typography';
6
- import { Grid } from '@availity/mui-layout';
7
- import { Button } from '@availity/mui-button';
8
- import { ControlledForm } from './ControlledForm';
9
3
  import { ControlledCheckbox } from './Checkbox';
10
-
11
- const SubmittedValues = () => {
12
- const {
13
- getValues,
14
- formState: { isSubmitSuccessful },
15
- } = useFormContext();
16
-
17
- return isSubmitSuccessful ? (
18
- <Paper sx={{ padding: '1.5rem', marginTop: '1.5rem' }}>
19
- <Typography variant="h2">Submitted Values</Typography>
20
- <pre data-testid="result">{JSON.stringify(getValues(), null, 2)}</pre>
21
- </Paper>
22
- ) : null;
23
- };
24
-
25
- const Actions = () => {
26
- const {
27
- formState: { isSubmitSuccessful },
28
- } = useFormContext();
29
- return (
30
- <Grid container direction="row" justifyContent="space-between">
31
- <Button type="submit" disabled={isSubmitSuccessful} children="Submit" />
32
- </Grid>
33
- );
34
- };
4
+ import { TestForm } from './UtilComponents';
35
5
 
36
6
  const onSubmit = jest.fn();
37
7
 
38
8
  describe('ControlledCheckbox', () => {
39
9
  test('should set the value and submit the form data', async () => {
40
- const screen = render(
41
- <ControlledForm onSubmit={onSubmit} values={{ controlledCheckbox: undefined }}>
42
- <FormControl>
43
- <FormLabel id="radio-group" component="div">
44
- Radio Group
45
- </FormLabel>
46
- <FormGroup>
47
- <FormControlLabel label="Option 1" control={<ControlledCheckbox name="option1" />} />
48
- <FormControlLabel label="Option 2" control={<ControlledCheckbox name="option2" />} />
49
- <FormControlLabel label="Option 3" control={<ControlledCheckbox name="option3" />} />
50
- </FormGroup>
51
- </FormControl>
52
- <Actions />
53
- <SubmittedValues />
54
- </ControlledForm>
10
+ const screen = render(
11
+ <TestForm onSubmit={onSubmit} UseFormOptions={{values: { option1: undefined, option2: undefined, option3: undefined }}}>
12
+ <FormControl>
13
+ <FormLabel id="radio-group" component="div">
14
+ Radio Group
15
+ </FormLabel>
16
+ <FormGroup>
17
+ <FormControlLabel label="Option 1" control={<ControlledCheckbox name="option1" />} />
18
+ <FormControlLabel label="Option 2" control={<ControlledCheckbox name="option2" />} />
19
+ <FormControlLabel label="Option 3" control={<ControlledCheckbox name="option3" />} />
20
+ </FormGroup>
21
+ </FormControl>
22
+ </TestForm>
55
23
  );
56
24
 
57
25
  const option1 = screen.getByText('Option 1');
@@ -1,37 +1,52 @@
1
1
  import { Checkbox, CheckboxProps } from '@availity/mui-checkbox';
2
- import { useFormContext, RegisterOptions, FieldValues } from 'react-hook-form';
2
+ import { RegisterOptions, FieldValues, Controller } from 'react-hook-form';
3
+ import { ControllerProps, DeprecatedRulesProps } from './Types';
3
4
 
4
- export type ControlledCheckboxProps = CheckboxProps & {
5
- name: string;
6
- } & Omit<
7
- RegisterOptions<FieldValues, string>,
8
- 'required' | 'max' | 'maxLength' | 'min' | 'minLength' | 'pattern' | 'validate'
9
- >;
5
+ export type ControlledCheckboxProps = Omit<CheckboxProps,
6
+ 'disabled' | 'onBlur' | 'onChange' | 'value' | 'name'
7
+ > & Pick<RegisterOptions<FieldValues, string>,
8
+ 'disabled' | 'onBlur' | 'onChange' | 'value'
9
+ > & ControllerProps
10
+ //TODO v1 - remove deprecated props
11
+ & Omit<DeprecatedRulesProps,
12
+ | 'required'
13
+ | 'max'
14
+ | 'maxLength'
15
+ | 'min'
16
+ | 'minLength'
17
+ | 'pattern'>;
10
18
 
11
19
  export const ControlledCheckbox = ({
12
20
  name,
13
- setValueAs,
14
21
  disabled,
15
22
  onChange,
16
23
  onBlur,
17
24
  value,
25
+ defaultValue = false,
26
+ rules = {},
18
27
  shouldUnregister,
19
28
  deps,
29
+ validate,
20
30
  ...rest
21
31
  }: ControlledCheckboxProps) => {
22
- const { register } = useFormContext();
23
32
  return (
24
- <Checkbox
25
- {...rest}
26
- {...register(name, {
27
- setValueAs,
28
- disabled,
33
+ <Controller
34
+ name={name}
35
+ defaultValue={defaultValue}
36
+ disabled={disabled}
37
+ rules={{
29
38
  onChange,
30
39
  onBlur,
31
40
  value,
32
41
  shouldUnregister,
33
42
  deps,
34
- })}
43
+ validate,
44
+ ...rules,
45
+ }}
46
+ shouldUnregister={shouldUnregister}
47
+ render={({ field }) => (
48
+ <Checkbox {...rest} {...field} checked={field.value} onChange={(e) => field.onChange(e.target.checked)} />
49
+ )}
35
50
  />
36
51
  );
37
52
  };
@@ -1,19 +1,18 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react';
2
2
  import { ControlledCodesAutocomplete } from './CodesAutocomplete';
3
- import { ControlledForm } from './ControlledForm';
4
3
  import { Button } from '@availity/mui-button';
5
- import { useFormContext } from 'react-hook-form';
6
4
  import { Paper } from '@availity/mui-paper';
7
5
  import { Typography } from '@availity/mui-typography';
8
6
  import { Grid } from '@availity/mui-layout';
9
7
  import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
10
- import { missingRHFprops } from '../../docs/propDefinitions';
8
+ import { AllControllerPropertiesCategorized, CodesAutocompletePropsCategorized } from './Types';
9
+ import { FormProvider, useForm } from '..';
11
10
 
12
11
  const meta: Meta<typeof ControlledCodesAutocomplete> = {
13
12
  title: 'Form Components/Controlled Form/Autocomplete/ControlledCodesAutocomplete',
14
13
  component: ControlledCodesAutocomplete,
15
14
  tags: ['autodocs'],
16
- argTypes: missingRHFprops,
15
+ argTypes: {...AllControllerPropertiesCategorized, ...CodesAutocompletePropsCategorized}
17
16
  };
18
17
 
19
18
  export default meta;
@@ -28,39 +27,25 @@ const client = new QueryClient({
28
27
 
29
28
  export const _ControlledCodesAutoComplete: StoryObj<typeof ControlledCodesAutocomplete> = {
30
29
  render: (args) => {
31
- const SubmittedValues = () => {
32
- const {
33
- getValues,
34
- formState: { isSubmitSuccessful },
35
- } = useFormContext();
30
+ const methods = useForm();
36
31
 
37
- return isSubmitSuccessful ? (
38
- <Paper sx={{ padding: '1.5rem', marginTop: '1.5rem' }}>
39
- <Typography variant="h2">Submitted Values</Typography>
40
- <pre>{JSON.stringify(getValues(), null, 2)}</pre>
41
- </Paper>
42
- ) : null;
43
- };
44
-
45
- const Actions = () => {
46
- const {
47
- reset,
48
- formState: { isSubmitSuccessful },
49
- } = useFormContext();
50
- return (
51
- <Grid container direction="row" justifyContent="space-between" marginTop={1}>
52
- <Button disabled={!isSubmitSuccessful} children="Reset" color="secondary" onClick={() => reset()} />
53
- <Button type="submit" disabled={isSubmitSuccessful} children="Submit" />
54
- </Grid>
55
- );
56
- };
57
32
  return (
58
33
  <QueryClientProvider client={client}>
59
- <ControlledForm values={{}} onSubmit={(data) => data}>
60
- <ControlledCodesAutocomplete {...args} />
61
- <Actions />
62
- <SubmittedValues />
63
- </ControlledForm>
34
+ <FormProvider {...methods}>
35
+ <form onSubmit={methods.handleSubmit((data) => data)}>
36
+ <ControlledCodesAutocomplete {...args} />
37
+ <Grid container direction="row" justifyContent="space-between" marginTop={1}>
38
+ <Button disabled={!methods?.formState?.isSubmitSuccessful} children="Reset" color="secondary" onClick={() => methods.reset()} />
39
+ <Button type="submit" disabled={methods?.formState?.isSubmitSuccessful} children="Submit" />
40
+ </Grid>
41
+ { methods?.formState?.isSubmitSuccessful ? (
42
+ <Paper sx={{ padding: '1.5rem', marginTop: '1.5rem' }}>
43
+ <Typography variant="h2">Submitted Values</Typography>
44
+ <pre data-testid="result">{JSON.stringify(methods.getValues(), null, 2)}</pre>
45
+ </Paper>
46
+ ) : null }
47
+ </form>
48
+ </FormProvider>
64
49
  </QueryClientProvider>
65
50
  );
66
51
  },
@@ -72,8 +57,9 @@ export const _ControlledCodesAutoComplete: StoryObj<typeof ControlledCodesAutoco
72
57
  helperText: 'Select a code from the list',
73
58
  placeholder: 'Select...',
74
59
  fullWidth: false,
60
+ required: true
75
61
  },
76
62
  limit: 15,
77
- required: 'This is required.',
63
+ rules: { required:'This is required.' },
78
64
  },
79
65
  };
@@ -1,39 +1,9 @@
1
1
  import { fireEvent, render, waitFor } from '@testing-library/react';
2
2
  import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
3
- import { Paper } from '@availity/mui-paper';
4
- import { Typography } from '@availity/mui-typography';
5
- import { useFormContext } from 'react-hook-form';
6
- import { Grid } from '@availity/mui-layout';
7
- import { Button } from '@availity/mui-button';
8
3
  // eslint-disable-next-line @nx/enforce-module-boundaries
9
4
  import { server } from '@availity/mock/src/lib/server';
10
- import { ControlledForm } from './ControlledForm';
11
5
  import { ControlledCodesAutocomplete } from './CodesAutocomplete';
12
-
13
- const SubmittedValues = () => {
14
- const {
15
- getValues,
16
- formState: { isSubmitSuccessful },
17
- } = useFormContext();
18
-
19
- return isSubmitSuccessful ? (
20
- <Paper sx={{ padding: '1.5rem', marginTop: '1.5rem' }}>
21
- <Typography variant="h2">Submitted Values</Typography>
22
- <pre data-testid="result">{JSON.stringify(getValues(), null, 2)}</pre>
23
- </Paper>
24
- ) : null;
25
- };
26
-
27
- const Actions = () => {
28
- const {
29
- formState: { isSubmitSuccessful },
30
- } = useFormContext();
31
- return (
32
- <Grid container direction="row" justifyContent="space-between">
33
- <Button type="submit" disabled={isSubmitSuccessful} children="Submit" />
34
- </Grid>
35
- );
36
- };
6
+ import { TestForm } from './UtilComponents';
37
7
 
38
8
  const onSubmit = jest.fn();
39
9
 
@@ -61,7 +31,7 @@ describe('ControlledAsyncAutocomplete', () => {
61
31
  test('should loadOptions successfully', async () => {
62
32
  const screen = render(
63
33
  <QueryClientProvider client={client}>
64
- <ControlledForm values={{}} onSubmit={onSubmit}>
34
+ <TestForm onSubmit={onSubmit}>
65
35
  <ControlledCodesAutocomplete
66
36
  name="controlledCodesAutocomplete"
67
37
  list="ABC"
@@ -73,11 +43,9 @@ describe('ControlledAsyncAutocomplete', () => {
73
43
  }}
74
44
  limit={15}
75
45
  />
76
- <Actions />
77
- <SubmittedValues />
78
- </ControlledForm>
79
- </QueryClientProvider>
80
- );
46
+ </TestForm>
47
+ </QueryClientProvider>
48
+ );
81
49
 
82
50
  const dropdown = screen.getByRole('combobox');
83
51
  fireEvent.click(dropdown);
@@ -87,23 +55,21 @@ describe('ControlledAsyncAutocomplete', () => {
87
55
  });
88
56
 
89
57
  test('should set the value and submit the form data', async () => {
90
- const screen = render(
91
- <QueryClientProvider client={client}>
92
- <ControlledForm values={{}} onSubmit={onSubmit}>
93
- <ControlledCodesAutocomplete
94
- name="controlledCodesAutocomplete"
95
- list="ABC"
96
- FieldProps={{
97
- label: 'Code Select',
98
- helperText: 'Select a code from the list',
99
- placeholder: 'Select...',
100
- fullWidth: false,
101
- }}
102
- limit={15}
103
- />
104
- <Actions />
105
- <SubmittedValues />
106
- </ControlledForm>
58
+ const screen = render(
59
+ <QueryClientProvider client={client}>
60
+ <TestForm onSubmit={onSubmit}>
61
+ <ControlledCodesAutocomplete
62
+ name="controlledCodesAutocomplete"
63
+ list="ABC"
64
+ FieldProps={{
65
+ label: 'Code Select',
66
+ helperText: 'Select a code from the list',
67
+ placeholder: 'Select...',
68
+ fullWidth: false,
69
+ }}
70
+ limit={15}
71
+ />
72
+ </TestForm>
107
73
  </QueryClientProvider>
108
74
  );
109
75
 
@@ -1,9 +1,14 @@
1
1
  import { CodesAutocomplete, CodesAutocompleteProps } from '@availity/mui-autocomplete';
2
- import { useFormContext, Controller, RegisterOptions, ControllerProps, FieldValues } from 'react-hook-form';
2
+ import { Controller, RegisterOptions, FieldValues } from 'react-hook-form';
3
+ import { ControllerProps, DeprecatedRulesProps } from './Types';
3
4
 
4
- export type ControlledCodesAutocompleteProps = Omit<CodesAutocompleteProps, 'name'> &
5
- Omit<RegisterOptions<FieldValues, string>, 'disabled' | 'valueAsNumber' | 'valueAsDate' | 'setValueAs'> &
6
- Pick<ControllerProps, 'defaultValue' | 'shouldUnregister' | 'name'>;
5
+ export type ControlledCodesAutocompleteProps = Omit<CodesAutocompleteProps,
6
+ 'onBlur' | 'onChange' | 'value' | 'name'
7
+ > & Pick<RegisterOptions<FieldValues, string>,
8
+ 'onBlur' | 'onChange' | 'value'
9
+ > & ControllerProps
10
+ //TODO v1 - remove deprecated props
11
+ & DeprecatedRulesProps;
7
12
 
8
13
  export const ControlledCodesAutocomplete = ({
9
14
  name,
@@ -15,18 +20,16 @@ export const ControlledCodesAutocomplete = ({
15
20
  onChange,
16
21
  pattern,
17
22
  required,
23
+ rules = {},
18
24
  shouldUnregister,
19
25
  validate,
20
26
  value,
21
27
  FieldProps,
22
28
  ...rest
23
29
  }: ControlledCodesAutocompleteProps) => {
24
- const { control, getFieldState } = useFormContext();
25
- const errorMessage = getFieldState(name).error?.message;
26
30
  return (
27
31
  <Controller
28
32
  name={name}
29
- control={control}
30
33
  defaultValue={defaultValue}
31
34
  rules={{
32
35
  deps,
@@ -39,25 +42,25 @@ export const ControlledCodesAutocomplete = ({
39
42
  shouldUnregister,
40
43
  validate,
41
44
  value,
45
+ ...rules,
42
46
  }}
43
47
  shouldUnregister={shouldUnregister}
44
- render={({ field: { onChange, value, onBlur } }) => (
48
+ render={({ field: { onChange, value, onBlur, ref }, fieldState: { error } }) => (
45
49
  <CodesAutocomplete
46
50
  {...rest}
47
51
  FieldProps={{
48
52
  ...FieldProps,
49
- required: typeof required === 'object' ? required.value : !!required,
50
- error: !!errorMessage,
51
- helperText:
52
- errorMessage && typeof errorMessage === 'string' ? (
53
- <>
54
- {errorMessage}
55
- <br />
56
- {FieldProps?.helperText}
57
- </>
58
- ) : (
59
- FieldProps?.helperText
60
- ),
53
+ error: !!error,
54
+ helperText: error?.message ? (
55
+ <>
56
+ {error.message}
57
+ <br />
58
+ {FieldProps?.helperText}
59
+ </>
60
+ ) : (
61
+ FieldProps?.helperText
62
+ ),
63
+ inputRef:ref
61
64
  }}
62
65
  onChange={(event, value, reason) => {
63
66
  if (reason === 'clear') {
@@ -11,6 +11,7 @@ import { ControlledTextField } from './TextField';
11
11
  import * as yup from 'yup';
12
12
  import { yupResolver } from '@hookform/resolvers/yup';
13
13
 
14
+ /** Deprecated. Use `FormProvider` and `useForm` directly. */
14
15
  const meta: Meta<typeof ControlledForm> = {
15
16
  title: 'Form Components/Controlled Form/ControlledForm',
16
17
  component: ControlledForm,
@@ -1,6 +1,7 @@
1
1
  import { FormHTMLAttributes } from 'react';
2
- import { useForm, SubmitHandler, FormProvider, Resolver } from 'react-hook-form';
2
+ import { useForm, SubmitHandler, FormProvider, Resolver, UseFormProps } from 'react-hook-form';
3
3
 
4
+ /** @deprecated Use `UseFormProps` directly with `useForm` and `FormProvider` */
4
5
  export type ControlledFormProps = {
5
6
  /** This function will receive the form data if form validation is successful. */
6
7
  onSubmit: SubmitHandler<any>;
@@ -13,6 +14,8 @@ export type ControlledFormProps = {
13
14
  * found here: https://github.com/react-hook-form/resolvers#quickstart
14
15
  */
15
16
  validationResolver?: (schema: unknown) => Resolver;
17
+ /** Additional react-hook-form `useForm` options, like `defaultValues` and validation `mode`. For more information see the [react-hook-form useForm docs](https://react-hook-form.com/docs/useform) */
18
+ additionalUseFormOptions?: Omit<UseFormProps, 'values' | 'resolver'>;
16
19
  } & FormHTMLAttributes<HTMLFormElement>;
17
20
 
18
21
  type UseFormOptions = {
@@ -20,8 +23,9 @@ type UseFormOptions = {
20
23
  resolver?: Resolver;
21
24
  };
22
25
 
23
- export const ControlledForm = ({ onSubmit, values, schema, validationResolver, ...rest }: ControlledFormProps) => {
24
- const useFormOptions: UseFormOptions = { values };
26
+ /** @deprecated Use `FormProvider` and `useForm` directly. */
27
+ export const ControlledForm = ({ onSubmit, values, schema, validationResolver, additionalUseFormOptions = {mode: 'onBlur'}, ...rest }: ControlledFormProps) => {
28
+ const useFormOptions: UseFormOptions = { values, ...additionalUseFormOptions };
25
29
  if (schema && validationResolver) {
26
30
  useFormOptions.resolver = validationResolver(schema);
27
31
  }
@@ -29,7 +33,7 @@ export const ControlledForm = ({ onSubmit, values, schema, validationResolver, .
29
33
 
30
34
  return (
31
35
  <FormProvider {...methods}>
32
- <form onSubmit={methods.handleSubmit(onSubmit)} {...rest} />
36
+ <form onSubmit={methods.handleSubmit(onSubmit)} noValidate {...rest} />
33
37
  </FormProvider>
34
38
  );
35
39
  };
@@ -1,54 +1,41 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react';
2
2
  import { ControlledDatepicker, ControlledDatepickerProps } from './Datepicker';
3
- import { ControlledForm } from './ControlledForm';
4
3
  import { Button } from '@availity/mui-button';
5
- import { useFormContext } from 'react-hook-form';
6
4
  import { Paper } from '@availity/mui-paper';
7
5
  import { Typography } from '@availity/mui-typography';
8
6
  import { Grid } from '@availity/mui-layout';
7
+ import { AllControllerPropertiesCategorized, DatepickerPropsCategorized } from './Types';
8
+ import { FormProvider, useForm } from '..';
9
9
 
10
10
  const meta: Meta<typeof ControlledDatepicker> = {
11
11
  title: 'Form Components/Controlled Form/ControlledDatepicker',
12
12
  component: ControlledDatepicker,
13
13
  tags: ['autodocs'],
14
+ argTypes: {...AllControllerPropertiesCategorized, ...DatepickerPropsCategorized}
14
15
  };
15
16
 
16
17
  export default meta;
17
18
 
18
19
  export const _ControlledInput: StoryObj<typeof ControlledDatepicker> = {
19
20
  render: (args: ControlledDatepickerProps) => {
20
- const SubmittedValues = () => {
21
- const {
22
- getValues,
23
- formState: { isSubmitSuccessful },
24
- } = useFormContext();
21
+ const methods = useForm();
25
22
 
26
- return isSubmitSuccessful ? (
27
- <Paper sx={{ padding: '1.5rem', marginTop: '1.5rem' }}>
28
- <Typography variant="h2">Submitted Values</Typography>
29
- <pre>{JSON.stringify(getValues(), null, 2)}</pre>
30
- </Paper>
31
- ) : null;
32
- };
33
-
34
- const Actions = () => {
35
- const {
36
- reset,
37
- formState: { isSubmitSuccessful },
38
- } = useFormContext();
39
- return (
40
- <Grid container direction="row" justifyContent="space-between" marginTop={1}>
41
- <Button disabled={!isSubmitSuccessful} children="Reset" color="secondary" onClick={() => reset()} />
42
- <Button type="submit" disabled={isSubmitSuccessful} children="Submit" />
43
- </Grid>
44
- );
45
- };
46
23
  return (
47
- <ControlledForm values={{ controlledInput: undefined }} onSubmit={(data) => data}>
48
- <ControlledDatepicker {...args} />
49
- <Actions />
50
- <SubmittedValues />
51
- </ControlledForm>
24
+ <FormProvider {...methods}>
25
+ <form onSubmit={methods.handleSubmit((data) => data)}>
26
+ <ControlledDatepicker {...args} />
27
+ <Grid container direction="row" justifyContent="space-between" marginTop={1}>
28
+ <Button disabled={!methods?.formState?.isSubmitSuccessful} children="Reset" color="secondary" onClick={() => methods.reset()} />
29
+ <Button type="submit" disabled={methods?.formState?.isSubmitSuccessful} children="Submit" />
30
+ </Grid>
31
+ { methods?.formState?.isSubmitSuccessful ? (
32
+ <Paper sx={{ padding: '1.5rem', marginTop: '1.5rem' }}>
33
+ <Typography variant="h2">Submitted Values</Typography>
34
+ <pre data-testid="result">{JSON.stringify(methods.getValues(), null, 2)}</pre>
35
+ </Paper>
36
+ ) : null }
37
+ </form>
38
+ </FormProvider>
52
39
  );
53
40
  },
54
41
  args: {