@availity/mui-datepicker 0.6.0 → 0.6.2

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,16 @@
2
2
 
3
3
  This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
4
4
 
5
+ ## [0.6.2](https://github.com/Availity/element/compare/@availity/mui-datepicker@0.6.1...@availity/mui-datepicker@0.6.2) (2025-02-18)
6
+
7
+ ### Dependency Updates
8
+
9
+ * `mui-textfield` updated to version `0.6.1`
10
+ ## [0.6.1](https://github.com/Availity/element/compare/@availity/mui-datepicker@0.6.0...@availity/mui-datepicker@0.6.1) (2025-02-05)
11
+
12
+ ### Dependency Updates
13
+
14
+ * `theme-provider` updated to version `0.6.0`
5
15
  ## [0.6.0](https://github.com/Availity/element/compare/@availity/mui-datepicker@0.5.2...@availity/mui-datepicker@0.6.0) (2025-02-04)
6
16
 
7
17
  ### Dependency Updates
@@ -0,0 +1,8 @@
1
+ import { Markdown, Source } from '@storybook/blocks';
2
+ import { Meta } from '@storybook/addon-docs';
3
+
4
+ import Docs from './DateRangePickerDocs.md?raw';
5
+
6
+ <Meta title="Form Components/Datepicker/Datepicker/Date Range Picker Docs" />
7
+
8
+ <Markdown>{Docs}</Markdown>
@@ -0,0 +1,294 @@
1
+ # DateRangePicker Docs
2
+
3
+ The `element` library has a `Datepicker` component that can be used to create your own `DateRangePicker`. There is not a `DateRangePicker` exported from the library.
4
+
5
+ ## Example
6
+
7
+ The following code block shows an example `DateRangePicker` using the `Datepicker` and `Grid` components.
8
+
9
+ ```tsx
10
+ import { Datepicker, Grid } from '@availity/element';
11
+ import type { Dayjs } from 'dayjs';
12
+
13
+ type DateRangePickerProps = {
14
+ startDate: Dayjs | null;
15
+ endDate: Dayjs | null;
16
+ onStartDateChange: (date: Dayjs | null) => void;
17
+ onEndDateChange: (date: Dayjs | null) => void;
18
+ startFieldProps?: {
19
+ label?: string;
20
+ helperText?: string;
21
+ helpTopicId?: string;
22
+ fullWidth?: boolean;
23
+ };
24
+ endFieldProps?: {
25
+ label?: string;
26
+ helperText?: string;
27
+ helpTopicId?: string;
28
+ fullWidth?: boolean;
29
+ };
30
+ };
31
+
32
+ const DateRangePicker = ({
33
+ startDate,
34
+ endDate,
35
+ onStartDateChange,
36
+ onEndDateChange,
37
+ startFieldProps = {
38
+ label: 'Start Date',
39
+ helperText: 'Select start date',
40
+ },
41
+ endFieldProps = {
42
+ label: 'End Date',
43
+ helperText: 'Select end date',
44
+ },
45
+ }: DateRangePickerProps) => {
46
+ return (
47
+ <>
48
+ <Grid container spacing={2}>
49
+ <Grid xs={12} sm={6}>
50
+ <Datepicker
51
+ value={startDate}
52
+ onChange={onStartDateChange}
53
+ FieldProps={startFieldProps}
54
+ maxDate={endDate ?? undefined} // Prevent selecting start date after end date
55
+ views={['day', 'month', 'year']}
56
+ />
57
+ </Grid>
58
+ <Grid xs={12} sm={6}>
59
+ <Datepicker
60
+ value={endDate}
61
+ onChange={onEndDateChange}
62
+ FieldProps={endFieldProps}
63
+ minDate={startDate ?? undefined} // Prevent selecting end date before start date
64
+ views={['day', 'month', 'year']}
65
+ />
66
+ </Grid>
67
+ </Grid>
68
+ </>
69
+ );
70
+ };
71
+ ```
72
+
73
+ ### Simple Usage
74
+
75
+ Below is an example of the `DateRangePicker` component we made above.
76
+
77
+ <Source />
78
+
79
+ ```tsx
80
+ import { useState } from 'react';
81
+ import { Dayjs } from 'dayjs';
82
+
83
+ import { DateRangePicker } from './DateRangePicker';
84
+
85
+ const MyComponent = () => {
86
+ const [startDate, setStartDate] = useState<Dayjs | null>(null);
87
+ const [endDate, setEndDate] = useState<Dayjs | null>(null);
88
+
89
+ return (
90
+ <DateRangePicker
91
+ // Required props
92
+ startDate={startDate}
93
+ endDate={endDate}
94
+ onStartDateChange={setStartDate}
95
+ onEndDateChange={setEndDate}
96
+ // Optional props with default values shown
97
+ startFieldProps={{
98
+ label: 'Start Date',
99
+ helperText: 'Select start date',
100
+ helpTopicId: '1234', // Optional help topic ID
101
+ fullWidth: false, // Optional width control
102
+ }}
103
+ endFieldProps={{
104
+ label: 'End Date',
105
+ helperText: 'Select end date',
106
+ helpTopicId: '1234', // Optional help topic ID
107
+ fullWidth: false, // Optional width control
108
+ }}
109
+ />
110
+ );
111
+ };
112
+ ```
113
+
114
+ ### Validation
115
+
116
+ The recommended way to validate the `DateRangePicker` is to use `yup`. Below we have an example of validating that the `endDate` is after the `startDate`.
117
+
118
+ ```tsx
119
+ import * as yup from 'yup';
120
+ import { Dayjs } from 'dayjs';
121
+
122
+ const dateRangeSchema = yup.object().shape({
123
+ startDate: yup.mixed<Dayjs | null>().nullable().required('Start date is required'),
124
+
125
+ endDate: yup
126
+ .mixed<Dayjs | null>()
127
+ .nullable()
128
+ .required('End date is required')
129
+ .test('is-after-start', 'End date must be after start date', function (endDate, context) {
130
+ const { startDate } = context.parent;
131
+
132
+ if (!startDate || !endDate) {
133
+ return true;
134
+ }
135
+
136
+ return endDate.isAfter(startDate) || endDate.isSame(startDate);
137
+ }),
138
+ });
139
+ ```
140
+
141
+ You can then use the created component and validation schema in a form with `react-hook-form`.
142
+
143
+ ```tsx
144
+ import { useForm, Controller } from 'react-hook-form';
145
+ import { yupResolver } from '@hookform/resolvers/yup';
146
+ import * as yup from 'yup';
147
+ import { Dayjs } from 'dayjs';
148
+
149
+ import { DateRangePicker } from './DateRangePicker';
150
+
151
+ interface DateRangeForm {
152
+ startDate: Dayjs | null;
153
+ endDate: Dayjs | null;
154
+ }
155
+
156
+ const dateRangeSchema = yup.object().shape({
157
+ startDate: yup.mixed<Dayjs | null>().nullable().required('Start date is required'),
158
+
159
+ endDate: yup
160
+ .mixed<Dayjs | null>()
161
+ .nullable()
162
+ .required('End date is required')
163
+ .test('is-after-start', 'End date must be after start date', function (endDate, context) {
164
+ const { startDate } = context.parent;
165
+
166
+ if (!startDate || !endDate) {
167
+ return true;
168
+ }
169
+
170
+ return endDate.isAfter(startDate) || endDate.isSame(startDate);
171
+ }),
172
+ });
173
+
174
+ const DateRangeForm = () => {
175
+ const {
176
+ control,
177
+ handleSubmit,
178
+ formState: { errors },
179
+ } = useForm<DateRangeForm>({
180
+ resolver: yupResolver(dateRangeSchema),
181
+ defaultValues: {
182
+ startDate: null,
183
+ endDate: null,
184
+ },
185
+ });
186
+ const DateRangeForm = () => {
187
+ const {
188
+ control,
189
+ handleSubmit,
190
+ formState: { errors },
191
+ watch,
192
+ } = useForm<DateRangeForm>({
193
+ resolver: yupResolver(dateRangeSchema),
194
+ defaultValues: {
195
+ startDate: null,
196
+ endDate: null,
197
+ },
198
+ mode: 'onChange', // Enable real-time validation
199
+ });
200
+
201
+ // Watch for changes in dates
202
+ const startDate = watch('startDate');
203
+ const endDate = watch('endDate');
204
+
205
+ // Optional: Add side effects when dates change
206
+ useEffect(() => {
207
+ if (startDate && endDate) {
208
+ // Perform any additional validation or business logic
209
+ console.log('Date range changed:', { startDate, endDate });
210
+ }
211
+ }, [startDate, endDate]);
212
+
213
+ const onSubmit = (data: DateRangeForm) => {
214
+ console.log('Form submitted:', data);
215
+ };
216
+
217
+ return (
218
+ <form onSubmit={handleSubmit(onSubmit)}>
219
+ <Controller
220
+ name="startDate"
221
+ control={control}
222
+ render={({ field: { onChange, value } }) => (
223
+ <Controller
224
+ name="endDate"
225
+ control={control}
226
+ render={({ field: { onChange: onEndChange, value: endValue } }) => (
227
+ <DateRangePicker
228
+ startDate={value}
229
+ endDate={endValue}
230
+ onStartDateChange={onChange}
231
+ onEndDateChange={onEndChange}
232
+ startFieldProps={{
233
+ helperText: errors.startDate?.message,
234
+ error: Boolean(errors.startDate),
235
+ label: 'Start Date',
236
+ fullWidth: true,
237
+ }}
238
+ endFieldProps={{
239
+ helperText: errors.endDate?.message,
240
+ error: Boolean(errors.endDate),
241
+ label: 'End Date',
242
+ fullWidth: true,
243
+ }}
244
+ />
245
+ )}
246
+ />
247
+ )}
248
+ />
249
+ <button type="submit" style={{ marginTop: '16px' }}>
250
+ Submit
251
+ </button>
252
+ </form>
253
+ );
254
+ };
255
+
256
+ const onSubmit = (data: DateRangeForm) => {
257
+ console.log(data);
258
+ };
259
+
260
+ return (
261
+ <form onSubmit={handleSubmit(onSubmit)}>
262
+ <Controller
263
+ name="startDate"
264
+ control={control}
265
+ render={({ field: { onChange, value } }) => (
266
+ <Controller
267
+ name="endDate"
268
+ control={control}
269
+ render={({ field: { onChange: onEndChange, value: endValue } }) => (
270
+ <DateRangePicker
271
+ startDate={value}
272
+ endDate={endValue}
273
+ onStartDateChange={onChange}
274
+ onEndDateChange={onEndChange}
275
+ startFieldProps={{
276
+ helperText: errors.startDate?.message,
277
+ error: Boolean(errors.startDate),
278
+ label: 'Start Date',
279
+ }}
280
+ endFieldProps={{
281
+ helperText: errors.endDate?.message,
282
+ error: Boolean(errors.endDate),
283
+ label: 'End Date',
284
+ }}
285
+ />
286
+ )}
287
+ />
288
+ )}
289
+ />
290
+ <button type="submit">Submit</button>
291
+ </form>
292
+ );
293
+ };
294
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@availity/mui-datepicker",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "description": "Availity MUI Datepicker Component - part of the @availity/element design system",
5
5
  "keywords": [
6
6
  "react",
@@ -41,7 +41,7 @@
41
41
  },
42
42
  "dependencies": {
43
43
  "@availity/mui-icon": "0.14.0",
44
- "@availity/mui-textfield": "0.7.0",
44
+ "@availity/mui-textfield": "0.7.1",
45
45
  "@mui/x-date-pickers": "^7.2.0",
46
46
  "dayjs": "^1.11.13"
47
47
  },
@@ -1,12 +1,12 @@
1
1
  // Each exported component in the package should have its own stories file
2
2
  import { useState } from 'react';
3
3
  import type { Meta, StoryObj } from '@storybook/react';
4
- import Grid from '@mui/material/Unstable_Grid2';
5
- import Paper from '@mui/material/Paper';
6
4
  import Typography from '@mui/material/Typography';
7
5
  import { MonthCalendar } from '@mui/x-date-pickers/MonthCalendar';
8
6
  import { YearCalendar } from '@mui/x-date-pickers/YearCalendar';
9
7
  import dayjs, { Dayjs } from 'dayjs';
8
+ import { Box, Grid } from '@availity/mui-layout';
9
+ import { Paper } from '@availity/mui-paper';
10
10
  import { Datepicker, DatepickerProps } from './Datepicker';
11
11
  import { DateCalendar } from './DateCalendar';
12
12
 
@@ -42,6 +42,65 @@ export const _Datepicker: StoryObj<typeof Datepicker> = {
42
42
  },
43
43
  };
44
44
 
45
+ type DateRangePickerProps = {
46
+ startDate: Dayjs | null;
47
+ endDate: Dayjs | null;
48
+ onStartDateChange: (date: Dayjs | null) => void;
49
+ onEndDateChange: (date: Dayjs | null) => void;
50
+ startFieldProps?: {
51
+ label?: string;
52
+ helperText?: string;
53
+ helpTopicId?: string;
54
+ fullWidth?: boolean;
55
+ };
56
+ endFieldProps?: {
57
+ label?: string;
58
+ helperText?: string;
59
+ helpTopicId?: string;
60
+ fullWidth?: boolean;
61
+ };
62
+ };
63
+
64
+ type DateRangePicker = (props: DateRangePickerProps) => JSX.Element;
65
+
66
+ export const _DateRangePicker: StoryObj<DateRangePicker> = {
67
+ render: () => {
68
+ const [startDate, setStartDate] = useState<Dayjs | null>(null);
69
+ const [endDate, setEndDate] = useState<Dayjs | null>(null);
70
+
71
+ return (
72
+ <Box sx={{ backgroundColor: 'background.paper', padding: '1.25rem' }}>
73
+ <Grid container spacing={2}>
74
+ <Grid xs={12} sm={6}>
75
+ <Datepicker
76
+ value={startDate}
77
+ onChange={setStartDate}
78
+ FieldProps={{
79
+ label: 'Start Date',
80
+ helperText: 'Select start date',
81
+ }}
82
+ maxDate={endDate ?? undefined} // Prevent selecting start date after end date
83
+ views={['day', 'month', 'year']}
84
+ />
85
+ </Grid>
86
+ <Grid xs={12} sm={6}>
87
+ <Datepicker
88
+ value={endDate}
89
+ onChange={setEndDate}
90
+ FieldProps={{
91
+ label: 'End Date',
92
+ helperText: 'Select end date',
93
+ }}
94
+ minDate={startDate ?? undefined} // Prevent selecting end date before start date
95
+ views={['day', 'month', 'year']}
96
+ />
97
+ </Grid>
98
+ </Grid>
99
+ </Box>
100
+ );
101
+ },
102
+ };
103
+
45
104
  export const _PickerViews: StoryObj<typeof DateCalendar> = {
46
105
  render: () => {
47
106
  const minDate = dayjs('2020-01-01T00:00:00.000');