@availity/mui-controlled-form 2.2.8 → 2.3.1

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/CHANGELOG.md CHANGED
@@ -2,6 +2,25 @@
2
2
 
3
3
  This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
4
4
 
5
+ ## [2.3.1](https://github.com/Availity/element/compare/@availity/mui-controlled-form@2.3.0...@availity/mui-controlled-form@2.3.1) (2026-05-27)
6
+
7
+ ### Dependency Updates
8
+
9
+ * `mui-autocomplete` updated to version `2.3.0`
10
+ * `mui-datepicker` updated to version `2.3.0`
11
+ * `mui-form-utils` updated to version `2.3.0`
12
+ * `mui-textfield` updated to version `2.3.0`
13
+ ## [2.3.0](https://github.com/Availity/element/compare/@availity/mui-controlled-form@2.2.8...@availity/mui-controlled-form@2.3.0) (2026-05-22)
14
+
15
+ ### Dependency Updates
16
+
17
+ * `mui-datepicker` updated to version `2.2.8`
18
+ * `theme-provider` updated to version `2.2.8`
19
+
20
+ ### Features
21
+
22
+ * **mui-datepicker:** add timepicker and update unfilled pickertextfield placeholder style ([cf95f5f](https://github.com/Availity/element/commit/cf95f5f1fdb1d29f1f66bd0a14f3dede759d834e))
23
+
5
24
  ## [2.2.8](https://github.com/Availity/element/compare/@availity/mui-controlled-form@2.2.7...@availity/mui-controlled-form@2.2.8) (2026-04-17)
6
25
 
7
26
  ### Dependency Updates
package/dist/index.d.mts CHANGED
@@ -5,7 +5,7 @@ export { FormProvider, SubmitHandler, UseFormProps, UseFormReturn, useForm, useF
5
5
  import { ChipTypeMap } from '@mui/material/Chip';
6
6
  import { CheckboxProps } from '@availity/mui-checkbox';
7
7
  import { ApiConfig } from '@availity/api-axios';
8
- import { DatepickerProps } from '@availity/mui-datepicker';
8
+ import { DatepickerProps, TimepickerProps } from '@availity/mui-datepicker';
9
9
  import { Dayjs } from 'dayjs';
10
10
  import { InputProps, RadioGroupProps, FormControlProps, SelectProps } from '@availity/mui-form-utils';
11
11
  import { TextFieldProps } from '@availity/mui-textfield';
@@ -97,4 +97,7 @@ declare const ControlledSelect: <Output = string, Input = unknown>({ name, defau
97
97
  type ControlledTextFieldProps<Output = string> = Omit<TextFieldProps, 'onBlur' | 'onChange' | 'value' | 'name'> & Pick<RegisterOptions<FieldValues, string>, 'onBlur' | 'onChange' | 'value'> & ControllerProps & TransformProp<string, Output>;
98
98
  declare const ControlledTextField: <Output = string>({ name, defaultValue, disabled, helperText, onBlur, onChange, rules, shouldUnregister, value, transform, ...rest }: ControlledTextFieldProps<Output>) => react_jsx_runtime.JSX.Element;
99
99
 
100
- export { ControlledAsyncAutocomplete, type ControlledAsyncAutocompleteProps, ControlledAutocomplete, type ControlledAutocompleteProps, ControlledCheckbox, type ControlledCheckboxProps, ControlledCodesAutocomplete, type ControlledCodesAutocompleteProps, ControlledDatepicker, type ControlledDatepickerProps, ControlledInput, type ControlledInputProps, type ControlledOrgAutocompleteProps, ControlledOrganizationAutocomplete, ControlledProviderAutocomplete, type ControlledProviderAutocompleteProps, ControlledRadioGroup, type ControlledRadioGroupProps, ControlledSelect, type ControlledSelectProps, ControlledTextField, type ControlledTextFieldProps };
100
+ type ControlledTimepickerProps<Output = Dayjs | null> = Omit<TimepickerProps, 'onBlur' | 'onChange' | 'value' | 'name'> & Pick<RegisterOptions<FieldValues, string>, 'onBlur' | 'onChange' | 'value'> & ControllerProps & TransformProp<Dayjs | null, Output>;
101
+ declare const ControlledTimepicker: <Output = Dayjs | null>({ name, defaultValue, onBlur, onChange, rules, shouldUnregister, value, FieldProps, transform, ...rest }: ControlledTimepickerProps<Output>) => react_jsx_runtime.JSX.Element;
102
+
103
+ export { ControlledAsyncAutocomplete, type ControlledAsyncAutocompleteProps, ControlledAutocomplete, type ControlledAutocompleteProps, ControlledCheckbox, type ControlledCheckboxProps, ControlledCodesAutocomplete, type ControlledCodesAutocompleteProps, ControlledDatepicker, type ControlledDatepickerProps, ControlledInput, type ControlledInputProps, type ControlledOrgAutocompleteProps, ControlledOrganizationAutocomplete, ControlledProviderAutocomplete, type ControlledProviderAutocompleteProps, ControlledRadioGroup, type ControlledRadioGroupProps, ControlledSelect, type ControlledSelectProps, ControlledTextField, type ControlledTextFieldProps, ControlledTimepicker, type ControlledTimepickerProps };
package/dist/index.d.ts CHANGED
@@ -5,7 +5,7 @@ export { FormProvider, SubmitHandler, UseFormProps, UseFormReturn, useForm, useF
5
5
  import { ChipTypeMap } from '@mui/material/Chip';
6
6
  import { CheckboxProps } from '@availity/mui-checkbox';
7
7
  import { ApiConfig } from '@availity/api-axios';
8
- import { DatepickerProps } from '@availity/mui-datepicker';
8
+ import { DatepickerProps, TimepickerProps } from '@availity/mui-datepicker';
9
9
  import { Dayjs } from 'dayjs';
10
10
  import { InputProps, RadioGroupProps, FormControlProps, SelectProps } from '@availity/mui-form-utils';
11
11
  import { TextFieldProps } from '@availity/mui-textfield';
@@ -97,4 +97,7 @@ declare const ControlledSelect: <Output = string, Input = unknown>({ name, defau
97
97
  type ControlledTextFieldProps<Output = string> = Omit<TextFieldProps, 'onBlur' | 'onChange' | 'value' | 'name'> & Pick<RegisterOptions<FieldValues, string>, 'onBlur' | 'onChange' | 'value'> & ControllerProps & TransformProp<string, Output>;
98
98
  declare const ControlledTextField: <Output = string>({ name, defaultValue, disabled, helperText, onBlur, onChange, rules, shouldUnregister, value, transform, ...rest }: ControlledTextFieldProps<Output>) => react_jsx_runtime.JSX.Element;
99
99
 
100
- export { ControlledAsyncAutocomplete, type ControlledAsyncAutocompleteProps, ControlledAutocomplete, type ControlledAutocompleteProps, ControlledCheckbox, type ControlledCheckboxProps, ControlledCodesAutocomplete, type ControlledCodesAutocompleteProps, ControlledDatepicker, type ControlledDatepickerProps, ControlledInput, type ControlledInputProps, type ControlledOrgAutocompleteProps, ControlledOrganizationAutocomplete, ControlledProviderAutocomplete, type ControlledProviderAutocompleteProps, ControlledRadioGroup, type ControlledRadioGroupProps, ControlledSelect, type ControlledSelectProps, ControlledTextField, type ControlledTextFieldProps };
100
+ type ControlledTimepickerProps<Output = Dayjs | null> = Omit<TimepickerProps, 'onBlur' | 'onChange' | 'value' | 'name'> & Pick<RegisterOptions<FieldValues, string>, 'onBlur' | 'onChange' | 'value'> & ControllerProps & TransformProp<Dayjs | null, Output>;
101
+ declare const ControlledTimepicker: <Output = Dayjs | null>({ name, defaultValue, onBlur, onChange, rules, shouldUnregister, value, FieldProps, transform, ...rest }: ControlledTimepickerProps<Output>) => react_jsx_runtime.JSX.Element;
102
+
103
+ export { ControlledAsyncAutocomplete, type ControlledAsyncAutocompleteProps, ControlledAutocomplete, type ControlledAutocompleteProps, ControlledCheckbox, type ControlledCheckboxProps, ControlledCodesAutocomplete, type ControlledCodesAutocompleteProps, ControlledDatepicker, type ControlledDatepickerProps, ControlledInput, type ControlledInputProps, type ControlledOrgAutocompleteProps, ControlledOrganizationAutocomplete, ControlledProviderAutocomplete, type ControlledProviderAutocompleteProps, ControlledRadioGroup, type ControlledRadioGroupProps, ControlledSelect, type ControlledSelectProps, ControlledTextField, type ControlledTextFieldProps, ControlledTimepicker, type ControlledTimepickerProps };
package/dist/index.js CHANGED
@@ -80,9 +80,10 @@ __export(index_exports, {
80
80
  ControlledRadioGroup: () => ControlledRadioGroup,
81
81
  ControlledSelect: () => ControlledSelect,
82
82
  ControlledTextField: () => ControlledTextField,
83
- FormProvider: () => import_react_hook_form9.FormProvider,
84
- useForm: () => import_react_hook_form9.useForm,
85
- useFormContext: () => import_react_hook_form9.useFormContext
83
+ ControlledTimepicker: () => ControlledTimepicker,
84
+ FormProvider: () => import_react_hook_form10.FormProvider,
85
+ useForm: () => import_react_hook_form10.useForm,
86
+ useFormContext: () => import_react_hook_form10.useFormContext
86
87
  });
87
88
  module.exports = __toCommonJS(index_exports);
88
89
 
@@ -720,8 +721,76 @@ var ControlledTextField = (_a) => {
720
721
  );
721
722
  };
722
723
 
723
- // src/index.ts
724
+ // src/lib/Timepicker.tsx
725
+ var import_mui_datepicker2 = require("@availity/mui-datepicker");
724
726
  var import_react_hook_form9 = require("react-hook-form");
727
+ var import_jsx_runtime12 = require("react/jsx-runtime");
728
+ var ControlledTimepicker = (_a) => {
729
+ var _b = _a, {
730
+ name,
731
+ defaultValue,
732
+ onBlur,
733
+ onChange,
734
+ rules = {},
735
+ shouldUnregister,
736
+ value,
737
+ FieldProps,
738
+ transform
739
+ } = _b, rest = __objRest(_b, [
740
+ "name",
741
+ "defaultValue",
742
+ "onBlur",
743
+ "onChange",
744
+ "rules",
745
+ "shouldUnregister",
746
+ "value",
747
+ "FieldProps",
748
+ "transform"
749
+ ]);
750
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
751
+ import_react_hook_form9.Controller,
752
+ {
753
+ name,
754
+ defaultValue,
755
+ rules: __spreadValues({
756
+ onBlur,
757
+ onChange,
758
+ shouldUnregister,
759
+ value
760
+ }, rules),
761
+ shouldUnregister,
762
+ render: ({ field: { onChange: onChange2, value: value2, onBlur: onBlur2, ref }, fieldState: { error } }) => {
763
+ var _a2;
764
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
765
+ import_mui_datepicker2.Timepicker,
766
+ __spreadProps(__spreadValues({}, rest), {
767
+ FieldProps: __spreadProps(__spreadValues({}, FieldProps), {
768
+ required: (typeof rules.required === "object" ? rules.required.value : !!rules.required) || (FieldProps == null ? void 0 : FieldProps.required),
769
+ error: !!error,
770
+ helperText: error ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
771
+ error.message,
772
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("br", {}),
773
+ FieldProps == null ? void 0 : FieldProps.helperText
774
+ ] }) : FieldProps == null ? void 0 : FieldProps.helperText,
775
+ inputRef: ref,
776
+ inputProps: {
777
+ onBlur: onBlur2
778
+ }
779
+ }),
780
+ onChange: (e) => {
781
+ var _a3, _b2;
782
+ return onChange2((_b2 = (_a3 = transform == null ? void 0 : transform.output) == null ? void 0 : _a3.call(transform, e)) != null ? _b2 : e);
783
+ },
784
+ value: ((_a2 = transform == null ? void 0 : transform.input) == null ? void 0 : _a2.call(transform, value2)) || value2 || null
785
+ })
786
+ );
787
+ }
788
+ }
789
+ );
790
+ };
791
+
792
+ // src/index.ts
793
+ var import_react_hook_form10 = require("react-hook-form");
725
794
  // Annotate the CommonJS export names for ESM import in node:
726
795
  0 && (module.exports = {
727
796
  ControlledAsyncAutocomplete,
@@ -735,6 +804,7 @@ var import_react_hook_form9 = require("react-hook-form");
735
804
  ControlledRadioGroup,
736
805
  ControlledSelect,
737
806
  ControlledTextField,
807
+ ControlledTimepicker,
738
808
  FormProvider,
739
809
  useForm,
740
810
  useFormContext
package/dist/index.mjs CHANGED
@@ -684,6 +684,74 @@ var ControlledTextField = (_a) => {
684
684
  );
685
685
  };
686
686
 
687
+ // src/lib/Timepicker.tsx
688
+ import { Timepicker } from "@availity/mui-datepicker";
689
+ import { Controller as Controller9 } from "react-hook-form";
690
+ import { Fragment as Fragment6, jsx as jsx12, jsxs as jsxs6 } from "react/jsx-runtime";
691
+ var ControlledTimepicker = (_a) => {
692
+ var _b = _a, {
693
+ name,
694
+ defaultValue,
695
+ onBlur,
696
+ onChange,
697
+ rules = {},
698
+ shouldUnregister,
699
+ value,
700
+ FieldProps,
701
+ transform
702
+ } = _b, rest = __objRest(_b, [
703
+ "name",
704
+ "defaultValue",
705
+ "onBlur",
706
+ "onChange",
707
+ "rules",
708
+ "shouldUnregister",
709
+ "value",
710
+ "FieldProps",
711
+ "transform"
712
+ ]);
713
+ return /* @__PURE__ */ jsx12(
714
+ Controller9,
715
+ {
716
+ name,
717
+ defaultValue,
718
+ rules: __spreadValues({
719
+ onBlur,
720
+ onChange,
721
+ shouldUnregister,
722
+ value
723
+ }, rules),
724
+ shouldUnregister,
725
+ render: ({ field: { onChange: onChange2, value: value2, onBlur: onBlur2, ref }, fieldState: { error } }) => {
726
+ var _a2;
727
+ return /* @__PURE__ */ jsx12(
728
+ Timepicker,
729
+ __spreadProps(__spreadValues({}, rest), {
730
+ FieldProps: __spreadProps(__spreadValues({}, FieldProps), {
731
+ required: (typeof rules.required === "object" ? rules.required.value : !!rules.required) || (FieldProps == null ? void 0 : FieldProps.required),
732
+ error: !!error,
733
+ helperText: error ? /* @__PURE__ */ jsxs6(Fragment6, { children: [
734
+ error.message,
735
+ /* @__PURE__ */ jsx12("br", {}),
736
+ FieldProps == null ? void 0 : FieldProps.helperText
737
+ ] }) : FieldProps == null ? void 0 : FieldProps.helperText,
738
+ inputRef: ref,
739
+ inputProps: {
740
+ onBlur: onBlur2
741
+ }
742
+ }),
743
+ onChange: (e) => {
744
+ var _a3, _b2;
745
+ return onChange2((_b2 = (_a3 = transform == null ? void 0 : transform.output) == null ? void 0 : _a3.call(transform, e)) != null ? _b2 : e);
746
+ },
747
+ value: ((_a2 = transform == null ? void 0 : transform.input) == null ? void 0 : _a2.call(transform, value2)) || value2 || null
748
+ })
749
+ );
750
+ }
751
+ }
752
+ );
753
+ };
754
+
687
755
  // src/index.ts
688
756
  import {
689
757
  FormProvider,
@@ -702,6 +770,7 @@ export {
702
770
  ControlledRadioGroup,
703
771
  ControlledSelect,
704
772
  ControlledTextField,
773
+ ControlledTimepicker,
705
774
  FormProvider,
706
775
  useForm,
707
776
  useFormContext2 as useFormContext
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@availity/mui-controlled-form",
3
- "version": "2.2.8",
3
+ "version": "2.3.1",
4
4
  "description": "Availity MUI/react-hook-form controlled form components - part of the @availity/element design system",
5
5
  "keywords": [
6
6
  "react",
@@ -40,15 +40,15 @@
40
40
  "publish:canary": "yarn npm publish --access public --tag canary"
41
41
  },
42
42
  "dependencies": {
43
- "@availity/mui-autocomplete": "^2.2.6",
43
+ "@availity/mui-autocomplete": "^2.2.7",
44
44
  "@availity/mui-checkbox": "^2.0.2",
45
- "@availity/mui-datepicker": "^2.1.0",
46
- "@availity/mui-form-utils": "^2.0.5",
47
- "@availity/mui-textfield": "^2.0.5",
45
+ "@availity/mui-datepicker": "^2.2.1",
46
+ "@availity/mui-form-utils": "^2.0.6",
47
+ "@availity/mui-textfield": "^2.0.6",
48
48
  "react-hook-form": "^7.55.0"
49
49
  },
50
50
  "devDependencies": {
51
- "@availity/api-axios": "^12.0.4",
51
+ "@availity/api-axios": "^12.2.1",
52
52
  "@availity/mui-button": "^2.0.2",
53
53
  "@availity/mui-layout": "^2.0.1",
54
54
  "@availity/mui-menu": "^2.0.2",
package/src/index.ts CHANGED
@@ -9,6 +9,7 @@ export * from './lib/ProviderAutocomplete';
9
9
  export * from './lib/RadioGroup';
10
10
  export * from './lib/Select';
11
11
  export * from './lib/TextField';
12
+ export * from './lib/Timepicker';
12
13
 
13
14
  export {
14
15
  FormProvider,
@@ -0,0 +1,104 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { ControlledTimepicker, ControlledTimepickerProps } from './Timepicker';
3
+ import { Button } from '@availity/mui-button';
4
+ import { Paper } from '@availity/mui-paper';
5
+ import { Typography } from '@availity/mui-typography';
6
+ import { Grid } from '@availity/mui-layout';
7
+ import { AllControllerPropertiesCategorized, TimepickerPropsCategorized } from './Types';
8
+ import { FormProvider, useForm } from '..';
9
+ import dayjs, { Dayjs } from 'dayjs';
10
+
11
+ const meta: Meta<typeof ControlledTimepicker> = {
12
+ title: 'Form Components/Controlled Form/ControlledTimepicker',
13
+ component: ControlledTimepicker,
14
+ tags: ['autodocs'],
15
+ argTypes: { ...AllControllerPropertiesCategorized, ...TimepickerPropsCategorized },
16
+ };
17
+
18
+ export default meta;
19
+
20
+ export const _ControlledTimePicker: StoryObj<typeof ControlledTimepicker> = {
21
+ render: (args: ControlledTimepickerProps) => {
22
+ const methods = useForm();
23
+
24
+ return (
25
+ <FormProvider {...methods}>
26
+ <form onSubmit={methods.handleSubmit((data) => data)}>
27
+ <ControlledTimepicker {...args} />
28
+ <Grid container direction="row" justifyContent="space-between" marginTop={1}>
29
+ <Button
30
+ disabled={!methods?.formState?.isSubmitSuccessful}
31
+ children="Reset"
32
+ color="secondary"
33
+ onClick={() => methods.reset()}
34
+ />
35
+ <Button type="submit" disabled={methods?.formState?.isSubmitSuccessful} children="Submit" />
36
+ </Grid>
37
+ {methods?.formState?.isSubmitSuccessful ? (
38
+ <Paper sx={{ padding: '1.5rem', marginTop: '1.5rem' }}>
39
+ <Typography variant="h2">Submitted Values</Typography>
40
+ <pre data-testid="result">{JSON.stringify(methods.getValues(), null, 2)}</pre>
41
+ </Paper>
42
+ ) : null}
43
+ </form>
44
+ </FormProvider>
45
+ );
46
+ },
47
+ args: {
48
+ name: 'controlledTimepicker',
49
+ FieldProps: {
50
+ fullWidth: false,
51
+ helperText: 'Help text for the field',
52
+ helpTopicId: '1234',
53
+ label: 'Time',
54
+ },
55
+ },
56
+ };
57
+
58
+ /**
59
+ * In this example, the underlying value is stored as a string in the form values,
60
+ * but the timepicker always receives a Dayjs object. The transform prop is used to
61
+ * convert the value to and from the format you want to store in the underlying
62
+ * form values. You can see the underlying value when submitting the form.
63
+ */
64
+ export const _Transform: StoryObj<typeof ControlledTimepicker> = {
65
+ render: (args: ControlledTimepickerProps) => {
66
+ const methods = useForm();
67
+
68
+ return (
69
+ <FormProvider {...methods}>
70
+ <form onSubmit={methods.handleSubmit((data) => data)}>
71
+ <ControlledTimepicker {...args} />
72
+ <Grid container direction="row" justifyContent="space-between" marginTop={1}>
73
+ <Button
74
+ disabled={!methods?.formState?.isSubmitSuccessful}
75
+ children="Reset"
76
+ color="secondary"
77
+ onClick={() => methods.reset()}
78
+ />
79
+ <Button type="submit" disabled={methods?.formState?.isSubmitSuccessful} children="Submit" />
80
+ </Grid>
81
+ {methods?.formState?.isSubmitSuccessful ? (
82
+ <Paper sx={{ padding: '1.5rem', marginTop: '1.5rem' }}>
83
+ <Typography variant="h2">Submitted Values</Typography>
84
+ <pre data-testid="result">{JSON.stringify(methods.getValues(), null, 2)}</pre>
85
+ </Paper>
86
+ ) : null}
87
+ </form>
88
+ </FormProvider>
89
+ );
90
+ },
91
+ args: {
92
+ transform: {
93
+ output: (value: Dayjs) => value?.format('hh:mm A'),
94
+ input: (value: string) => (value ? dayjs(value, 'hh:mm A') : null),
95
+ },
96
+ name: 'controlledTimepickerTransform',
97
+ FieldProps: {
98
+ fullWidth: false,
99
+ helperText: 'Help text for the field',
100
+ helpTopicId: '1234',
101
+ label: 'Time',
102
+ },
103
+ },
104
+ }
@@ -0,0 +1,110 @@
1
+ import { render, fireEvent, waitFor } from '@testing-library/react';
2
+ import { ThemeProvider } from '@availity/theme-provider';
3
+ import dayjs from 'dayjs';
4
+ import { ControlledTimepicker } from './Timepicker';
5
+ import { TestForm } from './UtilComponents';
6
+
7
+ const onSubmit = jest.fn();
8
+
9
+ describe('ControlledTimepicker', () => {
10
+ test('should render successfully and submit selection', async () => {
11
+ const screen = render(
12
+ <ThemeProvider>
13
+ <TestForm UseFormOptions={{ values: { controlledTimepicker: null } }} onSubmit={onSubmit}>
14
+ <ControlledTimepicker
15
+ name="controlledTimepicker"
16
+ FieldProps={{
17
+ fullWidth: false,
18
+ helperText: 'Help text for the field',
19
+ helpTopicId: '1234',
20
+ label: 'Time',
21
+ }}
22
+ />
23
+ </TestForm>
24
+ </ThemeProvider>
25
+ );
26
+ expect(screen.getAllByText('Time')).toBeTruthy();
27
+ const input = screen.getByLabelText('Choose time');
28
+ fireEvent.click(input);
29
+ const listboxes = screen.getAllByRole('listbox');
30
+ const hourOption = listboxes[0].querySelectorAll('[role="option"]');
31
+ fireEvent.click(hourOption[2]);
32
+
33
+ fireEvent.click(screen.getByText('OK'));
34
+ fireEvent.click(screen.getByText('Submit'));
35
+ await waitFor(() => expect(onSubmit).toHaveBeenCalledTimes(1));
36
+ const result = screen.getByTestId('result');
37
+ await waitFor(() => {
38
+ const controlledTimepickerValue = JSON.parse(result.innerHTML).controlledTimepicker;
39
+ expect(controlledTimepickerValue).toBeDefined();
40
+ expect(dayjs(controlledTimepickerValue).isValid()).toBeTruthy();
41
+ });
42
+ }, 10000);
43
+
44
+ describe('when using rules', () => {
45
+ describe('when required', () => {
46
+ test('should indicate it is required when passing a string', async () => {
47
+ const screen = render(
48
+ <ThemeProvider>
49
+ <TestForm UseFormOptions={{ values: { controlledTimepicker: null } }} onSubmit={onSubmit}>
50
+ <ControlledTimepicker
51
+ name="controlledTimepicker"
52
+ FieldProps={{
53
+ fullWidth: false,
54
+ helperText: 'Help text for the field',
55
+ helpTopicId: '1234',
56
+ label: 'Time',
57
+ }}
58
+ rules={{ required: 'This field is required' }}
59
+ />
60
+ </TestForm>
61
+ </ThemeProvider>
62
+ );
63
+
64
+ expect(screen.getAllByText('*')).toBeDefined();
65
+ });
66
+
67
+ test('should indicate it is required when passing an object with true', async () => {
68
+ const screen = render(
69
+ <ThemeProvider>
70
+ <TestForm UseFormOptions={{ values: { controlledTimepicker: null } }} onSubmit={onSubmit}>
71
+ <ControlledTimepicker
72
+ name="controlledTimepicker"
73
+ FieldProps={{
74
+ fullWidth: false,
75
+ helperText: 'Help text for the field',
76
+ helpTopicId: '1234',
77
+ label: 'Time',
78
+ }}
79
+ rules={{ required: { value: true, message: 'This field is required' } }}
80
+ />
81
+ </TestForm>
82
+ </ThemeProvider>
83
+ );
84
+
85
+ expect(screen.getAllByText('*')).toBeDefined();
86
+ });
87
+
88
+ test('should not indicate it is required when passing an object with false', async () => {
89
+ const screen = render(
90
+ <ThemeProvider>
91
+ <TestForm UseFormOptions={{ values: { controlledTimepicker: null } }} onSubmit={onSubmit}>
92
+ <ControlledTimepicker
93
+ name="controlledTimepicker"
94
+ FieldProps={{
95
+ fullWidth: false,
96
+ helperText: 'Help text for the field',
97
+ helpTopicId: '1234',
98
+ label: 'Time',
99
+ }}
100
+ rules={{ required: { value: false, message: 'This field is required' } }}
101
+ />
102
+ </TestForm>
103
+ </ThemeProvider>
104
+ );
105
+
106
+ expect(screen.queryAllByText('*')).toHaveLength(0);
107
+ });
108
+ });
109
+ });
110
+ });
@@ -0,0 +1,65 @@
1
+ import { Timepicker, TimepickerProps } from '@availity/mui-datepicker';
2
+ import { RegisterOptions, FieldValues, Controller } from 'react-hook-form';
3
+ import { ControllerProps, TransformProp } from './Types';
4
+ import { Dayjs } from 'dayjs';
5
+
6
+ export type ControlledTimepickerProps<Output = Dayjs | null> = Omit<
7
+ TimepickerProps,
8
+ 'onBlur' | 'onChange' | 'value' | 'name'
9
+ > &
10
+ Pick<RegisterOptions<FieldValues, string>, 'onBlur' | 'onChange' | 'value'> &
11
+ ControllerProps &
12
+ TransformProp<Dayjs | null, Output>;
13
+
14
+ export const ControlledTimepicker = <Output = Dayjs | null,>({
15
+ name,
16
+ defaultValue,
17
+ onBlur,
18
+ onChange,
19
+ rules = {},
20
+ shouldUnregister,
21
+ value,
22
+ FieldProps,
23
+ transform,
24
+ ...rest
25
+ }: ControlledTimepickerProps<Output>) => {
26
+ return (
27
+ <Controller
28
+ name={name}
29
+ defaultValue={defaultValue}
30
+ rules={{
31
+ onBlur,
32
+ onChange,
33
+ shouldUnregister,
34
+ value,
35
+ ...rules,
36
+ }}
37
+ shouldUnregister={shouldUnregister}
38
+ render={({ field: { onChange, value, onBlur, ref }, fieldState: { error } }) => (
39
+ <Timepicker
40
+ {...rest}
41
+ FieldProps={{
42
+ ...FieldProps,
43
+ required: (typeof rules.required === 'object' ? rules.required.value : !!rules.required) || FieldProps?.required,
44
+ error: !!error,
45
+ helperText: error ? (
46
+ <>
47
+ {error.message}
48
+ <br />
49
+ {FieldProps?.helperText}
50
+ </>
51
+ ) : (
52
+ FieldProps?.helperText
53
+ ),
54
+ inputRef: ref,
55
+ inputProps: {
56
+ onBlur: onBlur,
57
+ },
58
+ }}
59
+ onChange={(e) => onChange(transform?.output?.(e) ?? e)}
60
+ value={transform?.input?.(value) || value || null}
61
+ />
62
+ )}
63
+ />
64
+ );
65
+ };
package/src/lib/Types.tsx CHANGED
@@ -11,6 +11,7 @@ import {
11
11
  ControlledRadioGroupProps,
12
12
  ControlledSelectProps,
13
13
  ControlledTextFieldProps,
14
+ ControlledTimepickerProps,
14
15
  } from '..';
15
16
  import { HTMLAttributes } from 'react';
16
17
 
@@ -74,6 +75,14 @@ type DatepickerPropsObject = Record<
74
75
  { table: { category: 'Input Props' } }
75
76
  >;
76
77
 
78
+ type TimepickerPropsObject = Record<
79
+ keyof Omit<
80
+ ControlledTimepickerProps,
81
+ keyof AllControllerProps | keyof Omit<HTMLAttributes<undefined>, 'autoFocus' | 'className' | 'onError'>
82
+ >,
83
+ { table: { category: 'Input Props' } }
84
+ >;
85
+
77
86
  type ProviderAutocompletePropsObject = Record<
78
87
  keyof Omit<
79
88
  ControlledProviderAutocompleteProps,
@@ -429,6 +438,48 @@ export const DatepickerPropsCategorized: DatepickerPropsObject = {
429
438
  clearable: { table: { category: 'Input Props' } },
430
439
  };
431
440
 
441
+ export const TimepickerPropsCategorized: TimepickerPropsObject = {
442
+ autoFocus: { table: { category: 'Input Props' } },
443
+ className: { table: { category: 'Input Props' } },
444
+ onError: { table: { category: 'Input Props' } },
445
+ sx: { table: { category: 'Input Props' } },
446
+ label: { table: { category: 'Input Props' } },
447
+ view: { table: { category: 'Input Props' } },
448
+ readOnly: { table: { category: 'Input Props' } },
449
+ onClose: { table: { category: 'Input Props' } },
450
+ onOpen: { table: { category: 'Input Props' } },
451
+ open: { table: { category: 'Input Props' } },
452
+ FieldProps: { table: { category: 'Input Props' } },
453
+ disableFuture: { table: { category: 'Input Props' } },
454
+ disablePast: { table: { category: 'Input Props' } },
455
+ views: { table: { category: 'Input Props' } },
456
+ onViewChange: { table: { category: 'Input Props' } },
457
+ localeText: { table: { category: 'Input Props' } },
458
+ onAccept: { table: { category: 'Input Props' } },
459
+ viewRenderers: { table: { category: 'Input Props' } },
460
+ referenceDate: { table: { category: 'Input Props' } },
461
+ timezone: { table: { category: 'Input Props' } },
462
+ formatDensity: { table: { category: 'Input Props' } },
463
+ selectedSections: { table: { category: 'Input Props' } },
464
+ onSelectedSectionsChange: { table: { category: 'Input Props' } },
465
+ closeOnSelect: { table: { category: 'Input Props' } },
466
+ format: { table: { category: 'Input Props' } },
467
+ inputRef: { table: { category: 'Input Props' } },
468
+ placement: { table: { category: 'Input Props' } },
469
+ clearable: { table: { category: 'Input Props' } },
470
+ onClear: { table: { category: 'Input Props' } },
471
+ minutesStep: { table: { category: 'Input Props' } },
472
+ minTime: { table: { category: 'Input Props' } },
473
+ maxTime: { table: { category: 'Input Props' } },
474
+ shouldDisableTime: { table: { category: 'Input Props' } },
475
+ disableIgnoringDatePartForTimeValidation: { table: { category: 'Input Props' } },
476
+ ampm: { table: { category: 'Input Props' } },
477
+ skipDisabled: { table: { category: 'Input Props' } },
478
+ timeSteps: { table: { category: 'Input Props' } },
479
+ ampmInClock: { table: { category: 'Input Props' } },
480
+ thresholdToRenderTimeInASingleColumn: { table: { category: 'Input Props' } }
481
+ };
482
+
432
483
  export const CodesAutocompletePropsCategorized: CodesAutocompletePropsObject = {
433
484
  classes: { table: { category: 'Input Props' } },
434
485
  id: { table: { category: 'Input Props' } },