@agregio-solutions/design-system 1.90.1 → 1.92.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 (68) hide show
  1. package/dist/design-system.cjs +9 -5
  2. package/dist/design-system.js +14 -6
  3. package/dist/packages/components/Accordion/doc.md +342 -0
  4. package/dist/packages/components/Badge/doc.md +192 -0
  5. package/dist/packages/components/Breadcrumbs/doc.md +332 -0
  6. package/dist/packages/components/Button/doc.md +425 -0
  7. package/dist/packages/components/Calendar/doc.md +465 -0
  8. package/dist/packages/components/ChartLegend/doc.md +151 -0
  9. package/dist/packages/components/ChartTooltip/doc.md +124 -0
  10. package/dist/packages/components/Checkbox/doc.md +329 -0
  11. package/dist/packages/components/CheckboxGroup/doc.md +242 -0
  12. package/dist/packages/components/Chip/doc.md +99 -0
  13. package/dist/packages/components/Combobox/Combobox.d.ts +8 -0
  14. package/dist/packages/components/Combobox/doc.md +680 -0
  15. package/dist/packages/components/DataTable/doc.md +1124 -0
  16. package/dist/packages/components/DatePicker/doc.md +579 -0
  17. package/dist/packages/components/DateRangePicker/doc.md +638 -0
  18. package/dist/packages/components/Drawer/doc.md +338 -0
  19. package/dist/packages/components/Dropdown/Dropdown.d.ts +4 -0
  20. package/dist/packages/components/Dropdown/doc.md +205 -0
  21. package/dist/packages/components/EmptyState/doc.md +101 -0
  22. package/dist/packages/components/FileUpload/doc.md +449 -0
  23. package/dist/packages/components/Filter/doc.md +196 -0
  24. package/dist/packages/components/Header/doc.md +373 -0
  25. package/dist/packages/components/I18nProvider/doc.md +187 -0
  26. package/dist/packages/components/Icon/doc.md +63 -0
  27. package/dist/packages/components/Label/doc.md +60 -0
  28. package/dist/packages/components/LinearProgressBar/doc.md +148 -0
  29. package/dist/packages/components/Link/doc.md +206 -0
  30. package/dist/packages/components/List/doc.md +481 -0
  31. package/dist/packages/components/Loader/doc.md +53 -0
  32. package/dist/packages/components/Menu/Menu.d.ts +5 -1
  33. package/dist/packages/components/Menu/doc.md +231 -0
  34. package/dist/packages/components/Message/doc.md +166 -0
  35. package/dist/packages/components/Modal/doc.md +289 -0
  36. package/dist/packages/components/Navigation/doc.md +992 -0
  37. package/dist/packages/components/NavigationItem/doc.md +167 -0
  38. package/dist/packages/components/NotificationCard/doc.md +206 -0
  39. package/dist/packages/components/Notifications/doc.md +240 -0
  40. package/dist/packages/components/NumberField/doc.md +582 -0
  41. package/dist/packages/components/PageLayout/doc.md +651 -0
  42. package/dist/packages/components/Pagination/doc.md +227 -0
  43. package/dist/packages/components/Popover/doc.md +245 -0
  44. package/dist/packages/components/Radio/doc.md +370 -0
  45. package/dist/packages/components/RouterProvider/doc.md +64 -0
  46. package/dist/packages/components/SearchBar/doc.md +504 -0
  47. package/dist/packages/components/SegmentedControl/doc.md +398 -0
  48. package/dist/packages/components/Select/Select.d.ts +4 -0
  49. package/dist/packages/components/Select/doc.md +1133 -0
  50. package/dist/packages/components/Skeleton/doc.md +129 -0
  51. package/dist/packages/components/Slider/doc.md +362 -0
  52. package/dist/packages/components/Stepper/doc.md +104 -0
  53. package/dist/packages/components/Switch/doc.md +296 -0
  54. package/dist/packages/components/Tabs/doc.md +295 -0
  55. package/dist/packages/components/Tag/doc.md +81 -0
  56. package/dist/packages/components/TextInput/doc.md +490 -0
  57. package/dist/packages/components/TimeField/doc.md +353 -0
  58. package/dist/packages/components/Timeline/doc.md +1046 -0
  59. package/dist/packages/components/Toaster/doc.md +263 -0
  60. package/dist/packages/components/ToggleButton/doc.md +108 -0
  61. package/dist/packages/components/ToggleButtonGroup/doc.md +307 -0
  62. package/dist/packages/components/Tooltip/doc.md +206 -0
  63. package/dist/packages/components/YearMonthPicker/YearMonthPicker.d.ts +8 -0
  64. package/dist/packages/components/YearMonthPicker/doc.md +638 -0
  65. package/dist/public_docs/components.md +68 -0
  66. package/dist/public_docs/index.md +30 -0
  67. package/dist/public_docs/tokens.md +121 -0
  68. package/package.json +3 -2
@@ -0,0 +1,638 @@
1
+ # DateRangePicker
2
+
3
+ ## Props
4
+
5
+ The complete Props documentation with JS doc for this component is available at this path:
6
+
7
+ node_modules/@agregio-solutions/design-system/dist/packages/components/DateRangePicker/DateRangePicker.d.ts
8
+
9
+ ## Example usage
10
+
11
+ Here are the Storybook Stories.
12
+
13
+ Base stories:
14
+
15
+ ```tsx
16
+ import { Meta, StoryObj } from "@storybook/react-vite";
17
+ import DateRangePicker from "./DateRangePicker";
18
+ import { I18nProvider } from "react-aria-components";
19
+ import { fn } from "storybook/test";
20
+
21
+ const meta: Meta<typeof DateRangePicker> = {
22
+ component: DateRangePicker,
23
+ argTypes: {
24
+ label: { control: "text" },
25
+ value: { control: "text" },
26
+ timeZone: {
27
+ control: "select",
28
+ options: ["America/New_York", "Europe/Paris"],
29
+ },
30
+ shouldCloseOnSelect: { control: "boolean" },
31
+ description: { control: "text" },
32
+ helperText: { control: "text" },
33
+ errorHelperText: { control: "text" },
34
+ successHelperText: { control: "text" },
35
+ },
36
+ parameters: {
37
+ layout: "centered",
38
+ },
39
+ globals: {
40
+ backgrounds: { value: "light" },
41
+ },
42
+ decorators: [
43
+ (Story, context) => (
44
+ <I18nProvider locale={context.parameters.locale || "en-EN"}>
45
+ <Story />
46
+ </I18nProvider>
47
+ ),
48
+ ],
49
+ };
50
+ export default meta;
51
+
52
+ export const Playground: StoryObj<typeof DateRangePicker> = {
53
+ args: {
54
+ label: "Date Range Picker",
55
+ id: "date-range-picker",
56
+ onChange: fn(),
57
+ labelIconRight: "help_outline",
58
+ labelIconRightTooltip: "Additional information",
59
+ defaultValue: {
60
+ start: "2020-01-01T12:00:00",
61
+ end: "2020-01-10T12:00:00",
62
+ },
63
+ },
64
+ };
65
+
66
+ export const Empty: StoryObj<typeof DateRangePicker> = {
67
+ args: {
68
+ ...Playground.args,
69
+ defaultValue: undefined,
70
+ },
71
+ };
72
+
73
+ export const WithTime: StoryObj<typeof DateRangePicker> = {
74
+ args: {
75
+ ...Playground.args,
76
+ defaultValue: {
77
+ start: "2020-01-01T12:00:00",
78
+ end: "2020-01-10T12:00:00",
79
+ },
80
+ },
81
+ };
82
+
83
+ export const WithTimeZone: StoryObj<typeof DateRangePicker> = {
84
+ args: {
85
+ ...Playground.args,
86
+ defaultValue: {
87
+ start: "2020-01-01T12:00:00",
88
+ end: "2020-01-10T12:00:00",
89
+ },
90
+ timeZone: "America/New_York",
91
+ },
92
+ };
93
+
94
+ export const LocaleFR: StoryObj<typeof DateRangePicker> = {
95
+ parameters: {
96
+ locale: "fr-FR",
97
+ },
98
+ args: {
99
+ ...WithTimeZone.args,
100
+ },
101
+ };
102
+
103
+ export const WithMinValue: StoryObj<typeof DateRangePicker> = {
104
+ args: {
105
+ ...Playground.args,
106
+ defaultValue: {
107
+ start: "2020-01-15",
108
+ end: "2020-01-15",
109
+ },
110
+ minValue: "2020-01-10",
111
+ },
112
+ };
113
+
114
+ export const WithMaxValue: StoryObj<typeof DateRangePicker> = {
115
+ args: {
116
+ ...Playground.args,
117
+ defaultValue: {
118
+ start: "2020-01-08",
119
+ end: "2020-01-08",
120
+ },
121
+ maxValue: "2020-01-10",
122
+ },
123
+ };
124
+
125
+ export const Disabled: StoryObj<typeof DateRangePicker> = {
126
+ args: {
127
+ ...Playground.args,
128
+ isDisabled: true,
129
+ },
130
+ };
131
+
132
+ export const WithError: StoryObj<typeof DateRangePicker> = {
133
+ args: {
134
+ ...Playground.args,
135
+ helperText: undefined,
136
+ errorHelperText: "Error message",
137
+ errorHelperTextIcon: "error_outline",
138
+ },
139
+ };
140
+
141
+ export const WithSuccess: StoryObj<typeof DateRangePicker> = {
142
+ args: {
143
+ ...Playground.args,
144
+ helperText: undefined,
145
+ successHelperText: "Success message",
146
+ successHelperTextIcon: "check",
147
+ },
148
+ };
149
+
150
+ export const WithWarning: StoryObj<typeof DateRangePicker> = {
151
+ args: {
152
+ ...Playground.args,
153
+ helperText: undefined,
154
+ warningHelperText: "Warning message",
155
+ warningHelperTextIcon: "warning_amber",
156
+ },
157
+ };
158
+
159
+ export const Horizontal: StoryObj<typeof DateRangePicker> = {
160
+ args: {
161
+ ...Playground.args,
162
+ orientation: "horizontal",
163
+ },
164
+ };
165
+
166
+ export const Open: StoryObj<typeof DateRangePicker> = {
167
+ args: {
168
+ ...Playground.args,
169
+ isOpen: true,
170
+ },
171
+ };
172
+
173
+ export const FullWidth: StoryObj<typeof DateRangePicker> = {
174
+ parameters: {
175
+ layout: "padded",
176
+ },
177
+ args: {
178
+ ...Playground.args,
179
+ fullWidth: true,
180
+ },
181
+ };
182
+ ```
183
+
184
+ ## How to test this component
185
+
186
+ Here are some more advanced stories with more testing coverage and examples that you can read to understand how to test this component.
187
+
188
+ ```tsx
189
+ import { Meta, StoryObj } from "@storybook/react-vite";
190
+ import DateRangePicker from "../DateRangePicker";
191
+ import {
192
+ userEvent,
193
+ within,
194
+ screen,
195
+ fireEvent,
196
+ expect,
197
+ fn,
198
+ } from "storybook/test";
199
+ import { I18nProvider } from "react-aria-components";
200
+ import { useState } from "react";
201
+ import { Playground } from "../DateRangePicker.stories";
202
+ import { useController, useForm } from "react-hook-form";
203
+
204
+ const meta: Meta<typeof DateRangePicker> = {
205
+ component: DateRangePicker,
206
+ argTypes: {
207
+ label: { control: "text" },
208
+ },
209
+ parameters: {
210
+ layout: "centered",
211
+ chromatic: { disableSnapshot: true },
212
+ },
213
+ decorators: [
214
+ (Story) => (
215
+ <I18nProvider locale="en-EN">
216
+ <Story />
217
+ </I18nProvider>
218
+ ),
219
+ ],
220
+ };
221
+ export default meta;
222
+
223
+ export const ShouldSelectADateValue: StoryObj<typeof DateRangePicker> = {
224
+ args: {
225
+ ...Playground.args,
226
+ onChange: fn(),
227
+ defaultValue: {
228
+ start: "2020-01-01",
229
+ end: "2020-01-03",
230
+ },
231
+ },
232
+ play: async ({ canvasElement, args }) => {
233
+ const canvas = within(canvasElement);
234
+ const user = userEvent.setup({ delay: 50 });
235
+ await expect(canvas.getByLabelText(/month, Start Date/)).toHaveTextContent(
236
+ "1",
237
+ );
238
+ await expect(canvas.getByLabelText(/day, Start Date/)).toHaveTextContent(
239
+ "1",
240
+ );
241
+ await expect(canvas.getByLabelText(/year, Start Date/)).toHaveTextContent(
242
+ "2020",
243
+ );
244
+ await expect(canvas.getByLabelText(/month, End Date/)).toHaveTextContent(
245
+ "1",
246
+ );
247
+ await expect(canvas.getByLabelText(/day, End Date/)).toHaveTextContent("3");
248
+ await expect(canvas.getByLabelText(/year, End Date/)).toHaveTextContent(
249
+ "2020",
250
+ );
251
+
252
+ await user.click(canvas.getByLabelText("Open calendar Date Range Picker"));
253
+ await screen.findByLabelText("Sunday, January 5, 2020");
254
+ await fireEvent.click(screen.getByLabelText("Sunday, January 5, 2020"));
255
+ await fireEvent.click(screen.getByLabelText("Saturday, January 11, 2020"));
256
+ await expect(args.onChange).toHaveBeenCalledWith({
257
+ start: "2020-01-05",
258
+ end: "2020-01-11",
259
+ });
260
+ await expect(canvas.getByLabelText(/month, Start Date/)).toHaveTextContent(
261
+ "1",
262
+ );
263
+ await expect(canvas.getByLabelText(/day, Start Date/)).toHaveTextContent(
264
+ "5",
265
+ );
266
+ await expect(canvas.getByLabelText(/year, Start Date/)).toHaveTextContent(
267
+ "2020",
268
+ );
269
+ await expect(canvas.getByLabelText(/month, End Date/)).toHaveTextContent(
270
+ "1",
271
+ );
272
+ await expect(canvas.getByLabelText(/day, End Date/)).toHaveTextContent(
273
+ "11",
274
+ );
275
+ await expect(canvas.getByLabelText(/year, End Date/)).toHaveTextContent(
276
+ "2020",
277
+ );
278
+ },
279
+ };
280
+
281
+ export const ShouldSelectADateTimeValue: StoryObj<typeof DateRangePicker> = {
282
+ args: {
283
+ ...Playground.args,
284
+ defaultValue: {
285
+ start: "2020-01-01T10:00:00",
286
+ end: "2020-01-03T10:00:00",
287
+ },
288
+ },
289
+ play: async ({ canvasElement, args }) => {
290
+ const canvas = within(canvasElement);
291
+ const user = userEvent.setup({ delay: 50 });
292
+ await user.click(canvas.getByLabelText("Open calendar Date Range Picker"));
293
+ await screen.findByLabelText("Sunday, January 5, 2020");
294
+ await fireEvent.click(screen.getByLabelText("Sunday, January 5, 2020"));
295
+ await fireEvent.click(screen.getByLabelText("Saturday, January 11, 2020"));
296
+ await expect(args.onChange).toHaveBeenCalledWith({
297
+ start: "2020-01-05T10:00:00",
298
+ end: "2020-01-11T10:00:00",
299
+ });
300
+ },
301
+ };
302
+
303
+ export const ShouldSelectADateTimeValueWithTimezone: StoryObj<
304
+ typeof DateRangePicker
305
+ > = {
306
+ args: {
307
+ ...Playground.args,
308
+ timeZone: "Europe/Paris",
309
+ defaultValue: {
310
+ start: "2020-01-01T10:00:00",
311
+ end: "2020-01-03T10:00:00",
312
+ },
313
+ },
314
+ play: async ({ canvasElement, args }) => {
315
+ const canvas = within(canvasElement);
316
+ const user = userEvent.setup({ delay: 50 });
317
+ await user.click(canvas.getByLabelText("Open calendar Date Range Picker"));
318
+ await screen.findByLabelText("Sunday, January 5, 2020");
319
+ await fireEvent.click(screen.getByLabelText("Sunday, January 5, 2020"));
320
+ await fireEvent.click(screen.getByLabelText("Saturday, January 11, 2020"));
321
+ await expect(args.onChange).toHaveBeenCalledWith({
322
+ start: "2020-01-05T09:00:00.000Z",
323
+ end: "2020-01-11T09:00:00.000Z",
324
+ });
325
+ },
326
+ };
327
+
328
+ export const ShouldManageThePlaceholdervalueIfATimezoneIsGiven: StoryObj<
329
+ typeof DateRangePicker
330
+ > = {
331
+ args: {
332
+ ...Playground.args,
333
+ defaultValue: undefined,
334
+ timeZone: "Europe/Paris",
335
+ granularity: "minute",
336
+ },
337
+ play: async ({ canvasElement }) => {
338
+ const canvas = within(canvasElement);
339
+ await expect(canvas.getAllByText("GMT+1")).toHaveLength(2);
340
+ },
341
+ };
342
+
343
+ export const ExampleWithReactHookForm: StoryObj<typeof DateRangePicker> = {
344
+ render: () => {
345
+ const ParentComponent = () => {
346
+ const { control } = useForm({
347
+ defaultValues: {
348
+ date: {
349
+ start: "2020-01-01",
350
+ end: "2020-01-03",
351
+ },
352
+ },
353
+ });
354
+
355
+ const { field } = useController({ control, name: "date" });
356
+
357
+ return (
358
+ <>
359
+ <div>
360
+ Selected date : {field.value?.start} - {field.value?.end}
361
+ </div>
362
+ <DateRangePicker
363
+ {...field}
364
+ id="example-controlled date range picker"
365
+ label="Date Range Picker"
366
+ />
367
+ </>
368
+ );
369
+ };
370
+ return <ParentComponent />;
371
+ },
372
+ };
373
+
374
+ export const ControlledShouldSelectAValue: StoryObj<typeof DateRangePicker> = {
375
+ render: ExampleWithReactHookForm.render,
376
+ play: async ({ canvasElement }) => {
377
+ const canvas = within(canvasElement);
378
+ const user = userEvent.setup({ delay: 50 });
379
+ await canvas.findByText("Selected date : 2020-01-01 - 2020-01-03");
380
+ await user.click(canvas.getByLabelText("Open calendar Date Range Picker"));
381
+ await screen.findByLabelText("Sunday, January 5, 2020");
382
+ await fireEvent.click(screen.getByLabelText("Sunday, January 5, 2020"));
383
+ await fireEvent.click(screen.getByLabelText("Saturday, January 11, 2020"));
384
+ await canvas.findByText("Selected date : 2020-01-05 - 2020-01-11");
385
+ },
386
+ };
387
+
388
+ export const ExampleGranularity: StoryObj<typeof DateRangePicker> = {
389
+ render: () => {
390
+ function Example() {
391
+ const [date, setDate] = useState<null | {
392
+ start: string;
393
+ end: string;
394
+ }>({
395
+ start: "2021-04-07T18:45:22Z",
396
+ end: "2021-04-07T18:45:22Z",
397
+ });
398
+
399
+ return (
400
+ <>
401
+ <DateRangePicker
402
+ id="date-and-time"
403
+ label="Date and time"
404
+ granularity="second"
405
+ value={date}
406
+ onChange={setDate}
407
+ />
408
+
409
+ <DateRangePicker
410
+ id="date"
411
+ label="Date"
412
+ granularity="day"
413
+ value={date}
414
+ onChange={setDate}
415
+ />
416
+ </>
417
+ );
418
+ }
419
+ return <Example />;
420
+ },
421
+ };
422
+
423
+ export const ExampleGranularity2: StoryObj<typeof DateRangePicker> = {
424
+ render: () => {
425
+ function Example() {
426
+ return (
427
+ <>
428
+ <DateRangePicker
429
+ id="second"
430
+ label="Event date"
431
+ granularity="second"
432
+ />
433
+ <DateRangePicker id="day" label="Event date" granularity="day" />
434
+ </>
435
+ );
436
+ }
437
+ return <Example />;
438
+ },
439
+ };
440
+
441
+ export const ExampleInternationalCalendar: StoryObj<typeof DateRangePicker> = {
442
+ render: () => {
443
+ function Example() {
444
+ const [date, setDate] = useState<null | {
445
+ start: string;
446
+ end: string;
447
+ }>(null);
448
+
449
+ return (
450
+ <I18nProvider locale="hi-IN-u-ca-indian">
451
+ <DateRangePicker
452
+ id="international-calendar"
453
+ label="Date"
454
+ value={date}
455
+ onChange={setDate}
456
+ />
457
+ <p>
458
+ Selected date: {date?.start} - {date?.end}
459
+ </p>
460
+ </I18nProvider>
461
+ );
462
+ }
463
+ return <Example />;
464
+ },
465
+ };
466
+
467
+ export const ExampleMinMax: StoryObj<typeof DateRangePicker> = {
468
+ render: () => {
469
+ return (
470
+ <DateRangePicker
471
+ id="min-max"
472
+ label="Min Max"
473
+ minValue="2020-01-01"
474
+ maxValue="2020-01-10"
475
+ defaultValue={{
476
+ start: "2020-01-02",
477
+ end: "2020-01-07",
478
+ }}
479
+ />
480
+ );
481
+ },
482
+ };
483
+
484
+ export const ExampleUnavailableDates: StoryObj<typeof DateRangePicker> = {
485
+ render: () => {
486
+ return (
487
+ <DateRangePicker
488
+ id="unavailable-dates"
489
+ label="Unavailable dates"
490
+ isDateUnavailable={(stringDate) => {
491
+ const date = new Date(stringDate);
492
+ // 0 is Sunday, 6 is Saturday
493
+ if (date.getDay() === 0 || date.getDay() === 6) {
494
+ return true;
495
+ }
496
+ return false;
497
+ }}
498
+ />
499
+ );
500
+ },
501
+ };
502
+ ```
503
+
504
+ ## Developer notes
505
+
506
+ Here are the notes available for the developer on the built Storybook, you can read them to understand the component and how to use it.
507
+
508
+ ````mdx
509
+ import {
510
+ Canvas,
511
+ Meta,
512
+ Stories,
513
+ Controls,
514
+ Source,
515
+ Story,
516
+ } from "@storybook/addon-docs/blocks";
517
+
518
+ import * as DateRangePicker from "./DateRangePicker.stories";
519
+ import * as DateRangePickerTests from "./tests/DateRangePicker.stories";
520
+
521
+ <Meta of={DateRangePicker} />
522
+
523
+ # DateRangePicker
524
+
525
+ A date range picker combines two DateFields and a RangeCalendar popover to allow users to enter or select a date and time range.
526
+
527
+ <Canvas of={DateRangePicker.Playground} />
528
+ <Controls of={DateRangePicker.Playground} />
529
+
530
+ ## Example (with React Hook Form)
531
+
532
+ <Source of={DateRangePickerTests.ExampleWithReactHookForm} type="code" dark />
533
+
534
+ A date range picker can be built using two separate `<input type="date">` elements, but this is very limited in functionality, lacking in internationalization capabilities, inconsistent between browsers, and difficult to style.
535
+ DateRangePicker helps achieve accessible and international date and time range pickers that can be styled as needed.
536
+
537
+ - **Dates and times** – Support for dates and times with configurable granularity.
538
+ - **International** – Support for 13 calendar systems used around the world, including Gregorian, Buddhist, Islamic, Persian, and more. Locale-specific formatting, number systems, hour cycles, and right-to-left support are available as well.
539
+ - **Time zone aware** – Dates and times can optionally include a time zone. All modifications follow time zone rules such as daylight saving time.
540
+ - **Accessible** – Each date and time unit is displayed as an individually focusable and editable segment, which allows users an easy way to edit dates using the keyboard, in any date format and locale. Users can also open a calendar popover to select date ranges in a standard month grid. Localized screen reader messages are included to announce when the selection and visible date range change.
541
+ - **Touch friendly** – Date segments are editable using an easy to use numeric keypad, date ranges can be selected by dragging over dates in the calendar using a touch screen, and all interactions are accessible using touch-based screen readers.
542
+ - **Validation** – Integrates with HTML forms, supporting required, minimum and maximum values, unavailable dates, custom validation functions, realtime validation, and server-side validation errors.
543
+ - **Customizable** – As with all of React Aria, the DOM structure and styling of all elements can be fully customized.
544
+
545
+ Read [the React Aria blog post](https://react-spectrum.adobe.com/blog/date-and-time-pickers-for-all.html) for more details about the internationalization, accessibility, and user experience features implemented by DateRangePicker.
546
+
547
+ ## Value
548
+
549
+ A `DateRangePicker` displays a placeholder by default. An initial, uncontrolled value can be provided to the `DateRangePicker` using the `defaultValue` prop.
550
+ Alternatively, a controlled value can be provided using the `value` and `onchange` props.
551
+
552
+ Here is the type for the `value` prop (also valid for `defaultValue`, `onChange`, etc.):
553
+
554
+ ```ts
555
+ type DateRangePickerValue = null | {
556
+ start: string;
557
+ end: string;
558
+ };
559
+ ```
560
+
561
+ Date values are provided as string.
562
+ This component handles correct international date manipulation across calendars, time zones, and other localization concerns.
563
+ DateRangePicker supports values of the following string formats:
564
+
565
+ - `YYYY-MM-DD` -> a date without any time components. Use this type to represent dates where the time is not important, such as a birthday or an all day calendar event.
566
+ - `YYYY-MM-DDTHH:mm:ss` -> a date with a time, but not in any specific time zone. Use this type to represent times that occur at the same local time regardless of the time zone, such as the time of New Years Eve fireworks which always occur at midnight. Most times are better stored with a timezone (see below)
567
+ - `YYYY-MM-DDTHH:mm:ss+HH:mm` + "Europe/Paris" in `timezone` prop -> a date with a time in a specific time zone. Use this type to represent an exact moment in time at a particular location on Earth. The offset is optionnal, but if provided must be in the format `HH:mm` and match the timezone.
568
+
569
+ ## Granularity
570
+
571
+ The granularity prop allows you to control the smallest unit that is displayed by DatePicker.
572
+ By default, dates values are displayed with "day" granularity (year, month, and day) if there is no time part in it, and "minute" granularity if there is a time part.
573
+ More granular time values can be displayed by setting the granularity prop to "second".
574
+
575
+ In addition, when a value with a time is provided but you wish to only display the date, you can set the granularity to "day".
576
+ This has no effect on the actual value (it still has a time component), only on what fields are displayed.
577
+ In the following example, two DatePickers are synchronized with the same value, but display different granularities.
578
+
579
+ <Canvas of={DateRangePickerTests.ExampleGranularity} sourceState="shown" />
580
+
581
+ If no value or defaultValue prop is passed, then the granularity prop also affects which type of value is emitted from the onChange event.
582
+
583
+ <Canvas of={DateRangePickerTests.ExampleGranularity2} sourceState="shown" />
584
+
585
+ ## International calendar
586
+
587
+ DatePicker supports selecting dates in many calendar systems used around the world, including Gregorian, Hebrew, Indian, Islamic, Buddhist, and more.
588
+ Dates are automatically displayed in the appropriate calendar system for the user's locale.
589
+ The calendar system can be overridden using the [Unicode calendar locale extension](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/calendar#adding_a_calendar_in_the_locale_string), passed to the [I18nProvider](?path=/docs/components-i18nprovider--docs) component.
590
+
591
+ Selected dates passed to onChange always use the same calendar system as the value or defaultValue prop.
592
+ If no value or defaultValue is provided, then dates passed to onChange are always in the Gregorian calendar since this is the most commonly used.
593
+ This means that even though the user selects dates in their local calendar system, applications are able to deal with dates from all users consistently.
594
+
595
+ The below example displays a DatePicker in the Hindi language, using the Indian calendar.
596
+ Dates emitted from onChange are in the Gregorian calendar.
597
+
598
+ <Canvas
599
+ of={DateRangePickerTests.ExampleInternationalCalendar}
600
+ sourceState="shown"
601
+ />
602
+
603
+ ## Minimum and maximum values
604
+
605
+ The `minValue` and `maxValue` props can also be used to ensure the value is within a specific range.
606
+ Here is an example:
607
+
608
+ <Canvas of={DateRangePickerTests.ExampleMinMax} sourceState="shown" />
609
+
610
+ ## Unavailable dates
611
+
612
+ DatePicker supports marking certain dates as unavailable.
613
+ These dates remain focusable with the keyboard in the calendar so that navigation is consistent, but cannot be selected by the user.
614
+ When an unavailable date is entered into the date field, it is marked as invalid (but error message and submission prevention should be made by you on the form level).
615
+ The `isDateUnavailable` prop accepts a callback that is called to evaluate whether each visible date is unavailable.
616
+
617
+ This example show how to mark all week-ends as unavailable.
618
+
619
+ <Canvas of={DateRangePickerTests.ExampleUnavailableDates} sourceState="shown" />
620
+
621
+ ## How to test this component
622
+
623
+ First, click on the button that triggers the calendar opening. It will have a label name formatted like this: `Open calendar ${label}`.
624
+ For example: `getByLabelText("Open calendar Date Picker")` if the component has a label "Date Picker".
625
+
626
+ Second, you need to click on a date. The date will show up in a popup.
627
+ You may need to use `screen.getByLabelText` to target an element inside it. The label will have the corresponding date formatted in the language you provided with the `I18nProvider`.
628
+
629
+ For example, if the locale is "en", you can target a specific date visible in the actual opened calendar using the code `fireEvent.click(screen.getByLabelText("Thursday, January 2, 2020"))`.
630
+
631
+ You may notice that we used `fireEvent` because of a bug with `userEvent` on Firefox for some specific edge cases that (sadly) happen with this calendar.
632
+
633
+ If you want to target any other part of the component, just inspect the rendered HTML and you will see that every targetable element has a dedicated aria-label that you can target with `screen.getByLabelText`.
634
+
635
+ Here is a complete example of one of our tests using Storybook and Testing Library:
636
+
637
+ <Source of={DateRangePickerTests.ShouldSelectADateValue} type="code" dark />
638
+ ````