@hyphen/hyphen-components 6.15.1 → 7.0.0-beta.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/dist/components/Calendar/Calendar.d.ts +5 -0
- package/dist/components/Calendar/Calendar.stories.d.ts +12 -0
- package/dist/css/index.css +2 -3
- package/dist/css/utilities.css +8 -0
- package/dist/hyphen-components.cjs.development.js +644 -809
- package/dist/hyphen-components.cjs.development.js.map +1 -1
- package/dist/hyphen-components.cjs.production.min.js +1 -1
- package/dist/hyphen-components.cjs.production.min.js.map +1 -1
- package/dist/hyphen-components.esm.js +645 -808
- package/dist/hyphen-components.esm.js.map +1 -1
- package/dist/index.d.ts +1 -2
- package/package.json +2 -3
- package/src/components/Calendar/Calendar.mdx +28 -0
- package/src/components/Calendar/Calendar.stories.tsx +217 -0
- package/src/components/Calendar/Calendar.tsx +117 -0
- package/src/components/Formik/Formik.stories.tsx +10 -21
- package/src/index.ts +1 -2
- package/src/styles/utilities.scss +8 -0
- package/dist/components/DateInput/DateInput.d.ts +0 -57
- package/dist/components/DateInput/DateInput.stories.d.ts +0 -11
- package/dist/components/DatePicker/DatePicker.d.ts +0 -86
- package/dist/components/DatePicker/DatePicker.stories.d.ts +0 -13
- package/src/components/DateInput/DateInput.mdx +0 -61
- package/src/components/DateInput/DateInput.stories.tsx +0 -168
- package/src/components/DateInput/DateInput.test.tsx +0 -176
- package/src/components/DateInput/DateInput.tsx +0 -212
- package/src/components/DatePicker/DatePicker.mdx +0 -52
- package/src/components/DatePicker/DatePicker.module.scss +0 -603
- package/src/components/DatePicker/DatePicker.stories.tsx +0 -199
- package/src/components/DatePicker/DatePicker.test.tsx +0 -26
- package/src/components/DatePicker/DatePicker.tsx +0 -138
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { Canvas, Meta, ArgTypes } from '@storybook/addon-docs/blocks';
|
|
2
|
-
import { DateInput } from './DateInput';
|
|
3
|
-
import * as Stories from './DateInput.stories';
|
|
4
|
-
|
|
5
|
-
<Meta of={Stories} />
|
|
6
|
-
|
|
7
|
-
# DateInput
|
|
8
|
-
|
|
9
|
-
Use a DateInput to allow users to select a date close to today and place that date in an input field.
|
|
10
|
-
Avoid using this component if the user needs to enter a date that is many years in the past (i.e. birthday) or future.
|
|
11
|
-
For entering these types of dates we recommend using the `TextInput` component with a `date` mask. See an example here:
|
|
12
|
-
[TextInput Date Example](?path=/docs/components-textinput-overview--with-date-mask)
|
|
13
|
-
|
|
14
|
-
<Canvas isExpanded of={Stories.Basic} />
|
|
15
|
-
|
|
16
|
-
## Props
|
|
17
|
-
|
|
18
|
-
<ArgTypes of={DateInput} />
|
|
19
|
-
|
|
20
|
-
## Default
|
|
21
|
-
|
|
22
|
-
The DateInput is composed of 3 components. Each can be tailored based on their props. They are:
|
|
23
|
-
|
|
24
|
-
1. [DatePicker](?path=/docs/components-datepicker-overview--basic-example)
|
|
25
|
-
2. [Popover](?path=/docs/components-popover-overview--demo)
|
|
26
|
-
3. [TextInput](?path=/docs/components-textinput-overview--default-story)
|
|
27
|
-
|
|
28
|
-
The `DateInput` uses sensible defaults for these to allow for very straightforward ergonomics that allow users to
|
|
29
|
-
select dates with minimal work.
|
|
30
|
-
|
|
31
|
-
<Canvas of={Stories.Default} />
|
|
32
|
-
|
|
33
|
-
## Date Range
|
|
34
|
-
|
|
35
|
-
<Canvas of={Stories.DateRange} />
|
|
36
|
-
|
|
37
|
-
## With Min/Max dates
|
|
38
|
-
|
|
39
|
-
<Canvas of={Stories.WithMinAndMaxDates} />
|
|
40
|
-
|
|
41
|
-
## Custom Date Format
|
|
42
|
-
|
|
43
|
-
You can manipulate the format on the input field by using the `dateFormat` and `dateOptions`
|
|
44
|
-
props. Under the hood our component uses the [date-fns `format` function](https://date-fns.org/v2.16.1/docs/format)
|
|
45
|
-
to generate a string based on these options.
|
|
46
|
-
|
|
47
|
-
<Canvas of={Stories.CustomDateFormat} />
|
|
48
|
-
|
|
49
|
-
## On using onBlur event with DateInput
|
|
50
|
-
|
|
51
|
-
The input is technically blurred whenever the calendar popover is interacted but as far as the user
|
|
52
|
-
is concerned they are still interacting with the DateInput. Please keep this in mind when
|
|
53
|
-
triggering form validation after an onBlur event.
|
|
54
|
-
|
|
55
|
-
Make sure to pass the `onBlur` prop to the input via `textInputProps`.
|
|
56
|
-
|
|
57
|
-
<Canvas of={Stories.InputBlurEvent} />
|
|
58
|
-
|
|
59
|
-
## Component Design Tokens
|
|
60
|
-
|
|
61
|
-
This component shares component design tokens with all form controls. For a complete list of tokens, see the [Theming Form Controls documentation](/docs/theming-form-controls--custom-theme-form).
|
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
import React, { useState } from 'react';
|
|
2
|
-
import type { Meta } from '@storybook/react-vite';
|
|
3
|
-
import { DateInput } from './DateInput';
|
|
4
|
-
import { Box } from '../Box/Box';
|
|
5
|
-
|
|
6
|
-
const meta: Meta<typeof DateInput> = {
|
|
7
|
-
title: 'Components/DateInput',
|
|
8
|
-
component: DateInput,
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
export default meta;
|
|
12
|
-
|
|
13
|
-
export const Basic = () => (
|
|
14
|
-
<DateInput
|
|
15
|
-
datePickerProps={{
|
|
16
|
-
onChange() {},
|
|
17
|
-
}}
|
|
18
|
-
textInputProps={{
|
|
19
|
-
id: 'exampleDateInput',
|
|
20
|
-
name: 'selectDate',
|
|
21
|
-
label: 'Select a Date',
|
|
22
|
-
placeholder: 'e.g. 11/02/2020',
|
|
23
|
-
}}
|
|
24
|
-
/>
|
|
25
|
-
);
|
|
26
|
-
|
|
27
|
-
export const Default = () => {
|
|
28
|
-
const [selectedDate, setSelectedDate] = useState<Date | null | [Date, Date]>(
|
|
29
|
-
null
|
|
30
|
-
);
|
|
31
|
-
const handleClear = () => {
|
|
32
|
-
setSelectedDate(null);
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
return (
|
|
36
|
-
<DateInput
|
|
37
|
-
datePickerProps={{
|
|
38
|
-
selected: selectedDate instanceof Date ? selectedDate : null,
|
|
39
|
-
onChange: (date: Date | [Date, Date] | null) => setSelectedDate(date),
|
|
40
|
-
}}
|
|
41
|
-
textInputProps={{
|
|
42
|
-
placeholder: 'e.g. 11/02/2020',
|
|
43
|
-
onClear: handleClear,
|
|
44
|
-
id: 'defaultDatePicker',
|
|
45
|
-
name: 'selectDate',
|
|
46
|
-
label: 'Select Date',
|
|
47
|
-
}}
|
|
48
|
-
/>
|
|
49
|
-
);
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
export const DateRange = () => {
|
|
53
|
-
const [startDate, setStartDate] = useState<Date | [Date, Date] | null>(null);
|
|
54
|
-
const [endDate, setEndDate] = useState<Date | [Date, Date] | null>(null);
|
|
55
|
-
const setDate = ([startDate, endDate]: [Date, Date]) => {
|
|
56
|
-
setStartDate(startDate);
|
|
57
|
-
setEndDate(endDate);
|
|
58
|
-
};
|
|
59
|
-
const handleClear = () => {
|
|
60
|
-
setStartDate(null);
|
|
61
|
-
setEndDate(null);
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
return (
|
|
65
|
-
<DateInput
|
|
66
|
-
datePickerProps={{
|
|
67
|
-
// @ts-ignore - Type compatibility with onChange.
|
|
68
|
-
onChange: setDate,
|
|
69
|
-
selected: startDate as Date,
|
|
70
|
-
selectsRange: true,
|
|
71
|
-
startDate: startDate as Date,
|
|
72
|
-
endDate: endDate as Date,
|
|
73
|
-
}}
|
|
74
|
-
textInputProps={{
|
|
75
|
-
onClear: handleClear,
|
|
76
|
-
id: 'myDateRangePicker',
|
|
77
|
-
name: 'myDateRangePicker',
|
|
78
|
-
label: 'Select Date Range',
|
|
79
|
-
}}
|
|
80
|
-
/>
|
|
81
|
-
);
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
export const WithMinAndMaxDates = () => {
|
|
85
|
-
const [selectedDate, setSelectedDate] = useState<Date | [Date, Date] | null>(
|
|
86
|
-
null
|
|
87
|
-
);
|
|
88
|
-
const handleClear = () => {
|
|
89
|
-
setSelectedDate(null);
|
|
90
|
-
};
|
|
91
|
-
const min = new Date(2022, 6, 18);
|
|
92
|
-
min.setDate(min.getDate() - 10);
|
|
93
|
-
const max = new Date(2022, 6, 18);
|
|
94
|
-
max.setDate(max.getDate() + 10);
|
|
95
|
-
return (
|
|
96
|
-
<DateInput
|
|
97
|
-
datePickerProps={{
|
|
98
|
-
selected: selectedDate as Date,
|
|
99
|
-
maxDate: max,
|
|
100
|
-
minDate: min,
|
|
101
|
-
onChange: setSelectedDate,
|
|
102
|
-
}}
|
|
103
|
-
textInputProps={{
|
|
104
|
-
placeholder: 'e.g. 11/02/2020',
|
|
105
|
-
onClear: handleClear,
|
|
106
|
-
id: 'defaultDatePicker',
|
|
107
|
-
name: 'selectDate',
|
|
108
|
-
label: 'Select Date',
|
|
109
|
-
}}
|
|
110
|
-
/>
|
|
111
|
-
);
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
export const CustomDateFormat = () => {
|
|
115
|
-
const [selectedDate, setSelectedDate] = useState<Date | null | [Date, Date]>(
|
|
116
|
-
new Date('2020, 11, 3')
|
|
117
|
-
);
|
|
118
|
-
const handleClear = () => {
|
|
119
|
-
setSelectedDate(null);
|
|
120
|
-
};
|
|
121
|
-
return (
|
|
122
|
-
<Box gap="md">
|
|
123
|
-
<DateInput
|
|
124
|
-
dateFormat={'MMMM dd, yyyy'}
|
|
125
|
-
datePickerProps={{
|
|
126
|
-
selected: selectedDate as Date,
|
|
127
|
-
onChange: setSelectedDate,
|
|
128
|
-
}}
|
|
129
|
-
textInputProps={{
|
|
130
|
-
onClear: handleClear,
|
|
131
|
-
id: 'withCustomDateFormat',
|
|
132
|
-
name: 'selectDate',
|
|
133
|
-
label: 'Select Date',
|
|
134
|
-
}}
|
|
135
|
-
/>
|
|
136
|
-
<Box>
|
|
137
|
-
<p>
|
|
138
|
-
Selected Date (as ISO String):{' '}
|
|
139
|
-
{selectedDate ? (selectedDate as Date).toISOString() : null}
|
|
140
|
-
</p>
|
|
141
|
-
</Box>
|
|
142
|
-
</Box>
|
|
143
|
-
);
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
export const InputBlurEvent = () => {
|
|
147
|
-
const [selectedDate, setSelectedDate] = useState<Date | [Date, Date] | null>(
|
|
148
|
-
new Date('2020, 11, 3')
|
|
149
|
-
);
|
|
150
|
-
const handleTextInputBlur = () => {
|
|
151
|
-
alert('TextInput Blur Event');
|
|
152
|
-
};
|
|
153
|
-
return (
|
|
154
|
-
<DateInput
|
|
155
|
-
dateFormat={'MMMM dd, yyyy'}
|
|
156
|
-
datePickerProps={{
|
|
157
|
-
selected: selectedDate as Date,
|
|
158
|
-
onChange: setSelectedDate,
|
|
159
|
-
}}
|
|
160
|
-
textInputProps={{
|
|
161
|
-
id: 'withCustomDateFormat',
|
|
162
|
-
name: 'selectDate',
|
|
163
|
-
label: 'Select Date',
|
|
164
|
-
onBlur: handleTextInputBlur,
|
|
165
|
-
}}
|
|
166
|
-
/>
|
|
167
|
-
);
|
|
168
|
-
};
|
|
@@ -1,176 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
|
3
|
-
import { DateInput } from './DateInput';
|
|
4
|
-
|
|
5
|
-
describe('DateInput', () => {
|
|
6
|
-
describe('Default', () => {
|
|
7
|
-
it('renders a DateInput component with defaults', () => {
|
|
8
|
-
render(
|
|
9
|
-
<DateInput
|
|
10
|
-
textInputProps={{
|
|
11
|
-
id: 'myInput',
|
|
12
|
-
label: 'Select Date',
|
|
13
|
-
}}
|
|
14
|
-
datePickerProps={{
|
|
15
|
-
onChange: () => null,
|
|
16
|
-
}}
|
|
17
|
-
/>
|
|
18
|
-
);
|
|
19
|
-
|
|
20
|
-
const input = screen.getByLabelText('Select Date');
|
|
21
|
-
expect(input).toBeInTheDocument();
|
|
22
|
-
});
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
describe('Popover', () => {
|
|
26
|
-
it('keeps popover open after only start date is picked in a range', async () => {
|
|
27
|
-
const date = new Date(2020, 0, 1);
|
|
28
|
-
render(
|
|
29
|
-
<DateInput
|
|
30
|
-
textInputProps={{
|
|
31
|
-
id: 'myInput',
|
|
32
|
-
label: 'Select Date',
|
|
33
|
-
}}
|
|
34
|
-
datePickerProps={{
|
|
35
|
-
onChange: () => null,
|
|
36
|
-
openToDate: date,
|
|
37
|
-
startDate: date,
|
|
38
|
-
selected: date,
|
|
39
|
-
selectsRange: true,
|
|
40
|
-
endDate: null,
|
|
41
|
-
}}
|
|
42
|
-
/>
|
|
43
|
-
);
|
|
44
|
-
const input = screen.getByLabelText('Select Date');
|
|
45
|
-
fireEvent.click(input);
|
|
46
|
-
const popoverContainer =
|
|
47
|
-
document.getElementsByClassName('PopoverContent');
|
|
48
|
-
await waitFor(() => expect(popoverContainer[0]).toBeInTheDocument());
|
|
49
|
-
// Simulate picking start date (should not close popover)
|
|
50
|
-
// (Assume date button is present)
|
|
51
|
-
// Popover should still be open
|
|
52
|
-
expect(document.getElementsByClassName('PopoverContent').length).toBe(1);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it('opens the Popover when the input is clicked', async () => {
|
|
56
|
-
render(
|
|
57
|
-
<DateInput
|
|
58
|
-
textInputProps={{
|
|
59
|
-
id: 'myInput',
|
|
60
|
-
label: 'Select Date',
|
|
61
|
-
}}
|
|
62
|
-
datePickerProps={{
|
|
63
|
-
onChange: () => null,
|
|
64
|
-
}}
|
|
65
|
-
/>
|
|
66
|
-
);
|
|
67
|
-
|
|
68
|
-
const input = screen.getByLabelText('Select Date');
|
|
69
|
-
fireEvent.click(input);
|
|
70
|
-
|
|
71
|
-
const popoverContainer =
|
|
72
|
-
document.getElementsByClassName('PopoverContent');
|
|
73
|
-
await waitFor(() =>
|
|
74
|
-
expect(popoverContainer[0]).toHaveAttribute('data-side', 'bottom')
|
|
75
|
-
);
|
|
76
|
-
await waitFor(() =>
|
|
77
|
-
expect(popoverContainer[0]).toHaveAttribute('data-align', 'start')
|
|
78
|
-
);
|
|
79
|
-
});
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
describe('Date Formatting', () => {
|
|
83
|
-
it('formats the date when a format is passed', async () => {
|
|
84
|
-
const date = new Date(1995, 11, 14);
|
|
85
|
-
render(
|
|
86
|
-
<DateInput
|
|
87
|
-
dateFormat="yyyy/MM/dd"
|
|
88
|
-
textInputProps={{
|
|
89
|
-
id: 'myInput',
|
|
90
|
-
label: 'Select Date',
|
|
91
|
-
}}
|
|
92
|
-
datePickerProps={{
|
|
93
|
-
onChange: () => null,
|
|
94
|
-
openToDate: date,
|
|
95
|
-
selected: date,
|
|
96
|
-
}}
|
|
97
|
-
/>
|
|
98
|
-
);
|
|
99
|
-
|
|
100
|
-
const input = screen.getByLabelText('Select Date');
|
|
101
|
-
expect(input).toBeInTheDocument();
|
|
102
|
-
expect(input).toHaveAttribute('value', '1995/12/14');
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
it('formats both dates when range is being selected', async () => {
|
|
106
|
-
const dateOne = new Date(1995, 11, 14);
|
|
107
|
-
const dateTwo = new Date(1995, 11, 16);
|
|
108
|
-
render(
|
|
109
|
-
<DateInput
|
|
110
|
-
dateFormat="yyyy/MM/dd"
|
|
111
|
-
textInputProps={{
|
|
112
|
-
id: 'myInput',
|
|
113
|
-
label: 'Select Date',
|
|
114
|
-
}}
|
|
115
|
-
datePickerProps={{
|
|
116
|
-
onChange: () => null,
|
|
117
|
-
openToDate: dateOne,
|
|
118
|
-
startDate: dateOne,
|
|
119
|
-
endDate: dateTwo,
|
|
120
|
-
selectsRange: true,
|
|
121
|
-
}}
|
|
122
|
-
/>
|
|
123
|
-
);
|
|
124
|
-
|
|
125
|
-
const input = screen.getByLabelText('Select Date');
|
|
126
|
-
expect(input).toBeInTheDocument();
|
|
127
|
-
expect(input).toHaveAttribute('value', '1995/12/14 - 1995/12/16');
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
it('formats one date if selecting range', async () => {
|
|
131
|
-
const dateOne = null;
|
|
132
|
-
const dateTwo = new Date(1995, 11, 16);
|
|
133
|
-
const { rerender } = render(
|
|
134
|
-
<DateInput
|
|
135
|
-
dateFormat="yyyy/MM/dd"
|
|
136
|
-
textInputProps={{
|
|
137
|
-
id: 'myInput',
|
|
138
|
-
label: 'Select Date',
|
|
139
|
-
}}
|
|
140
|
-
datePickerProps={{
|
|
141
|
-
onChange: () => null,
|
|
142
|
-
openToDate: dateTwo,
|
|
143
|
-
startDate: dateOne,
|
|
144
|
-
endDate: dateTwo,
|
|
145
|
-
selectsRange: true,
|
|
146
|
-
}}
|
|
147
|
-
/>
|
|
148
|
-
);
|
|
149
|
-
|
|
150
|
-
const input = screen.getByLabelText('Select Date');
|
|
151
|
-
expect(input).toBeInTheDocument();
|
|
152
|
-
expect(input).toHaveAttribute('value', ' - 1995/12/16');
|
|
153
|
-
|
|
154
|
-
rerender(
|
|
155
|
-
<DateInput
|
|
156
|
-
dateFormat="yyyy/MM/dd"
|
|
157
|
-
textInputProps={{
|
|
158
|
-
id: 'myInput',
|
|
159
|
-
label: 'Select Date',
|
|
160
|
-
}}
|
|
161
|
-
datePickerProps={{
|
|
162
|
-
onChange: () => null,
|
|
163
|
-
openToDate: dateTwo,
|
|
164
|
-
startDate: dateTwo,
|
|
165
|
-
endDate: dateOne,
|
|
166
|
-
selectsRange: true,
|
|
167
|
-
}}
|
|
168
|
-
/>
|
|
169
|
-
);
|
|
170
|
-
|
|
171
|
-
const inputTwo = screen.getByLabelText('Select Date');
|
|
172
|
-
expect(inputTwo).toBeInTheDocument();
|
|
173
|
-
expect(inputTwo).toHaveAttribute('value', '1995/12/16 - ');
|
|
174
|
-
});
|
|
175
|
-
});
|
|
176
|
-
});
|
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
import React, { FC, useState } from 'react';
|
|
2
|
-
import format from 'date-fns/format';
|
|
3
|
-
import { DatePicker, DatePickerProps } from '../DatePicker/DatePicker';
|
|
4
|
-
import { TextInput, TextInputProps } from '../TextInput/TextInput';
|
|
5
|
-
import {
|
|
6
|
-
Popover,
|
|
7
|
-
PopoverContent,
|
|
8
|
-
PopoverPortal,
|
|
9
|
-
PopoverTrigger,
|
|
10
|
-
} from '../Popover/Popover';
|
|
11
|
-
import { useOpenClose } from '../../hooks';
|
|
12
|
-
|
|
13
|
-
export interface DateInputProps {
|
|
14
|
-
/**
|
|
15
|
-
* Props object for DatePicker component.
|
|
16
|
-
*/
|
|
17
|
-
datePickerProps: DatePickerProps;
|
|
18
|
-
/**
|
|
19
|
-
* Props object for TextInput component.
|
|
20
|
-
*/
|
|
21
|
-
textInputProps: Omit<TextInputProps, 'onChange'>;
|
|
22
|
-
/**
|
|
23
|
-
* Format for final date to be displayed.
|
|
24
|
-
* Relies on date-fns/format --> https://date-fns.org/v1.9.0/docs/format
|
|
25
|
-
*/
|
|
26
|
-
dateFormat?: string;
|
|
27
|
-
/**
|
|
28
|
-
* Additional settings for formatting date.
|
|
29
|
-
*/
|
|
30
|
-
dateOptions?: {
|
|
31
|
-
/**
|
|
32
|
-
* The user's locale.
|
|
33
|
-
*/
|
|
34
|
-
locale?: globalThis.Locale | undefined;
|
|
35
|
-
/**
|
|
36
|
-
* Start of week.
|
|
37
|
-
*/
|
|
38
|
-
weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | undefined;
|
|
39
|
-
/**
|
|
40
|
-
* Should determine which week is week 1 of a new year.
|
|
41
|
-
*/
|
|
42
|
-
firstWeekContainsDate?: number | undefined;
|
|
43
|
-
/**
|
|
44
|
-
* Whether to accept unicode tokens in format.
|
|
45
|
-
* See here --> https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md
|
|
46
|
-
*/
|
|
47
|
-
useAdditionalWeekYearTokens?: boolean | undefined;
|
|
48
|
-
/**
|
|
49
|
-
* Whether to accept unicode tokens in format.
|
|
50
|
-
* See here --> https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md
|
|
51
|
-
*/
|
|
52
|
-
useAdditionalDayOfYearTokens?: boolean | undefined;
|
|
53
|
-
};
|
|
54
|
-
/**
|
|
55
|
-
* Props to pass down to the Popover component.
|
|
56
|
-
*/
|
|
57
|
-
popoverProps?: {
|
|
58
|
-
side: 'top' | 'bottom' | 'left' | 'right';
|
|
59
|
-
align: 'start' | 'center' | 'end';
|
|
60
|
-
};
|
|
61
|
-
/**
|
|
62
|
-
* Additional props to be spread to the `TextInput` element.
|
|
63
|
-
*/
|
|
64
|
-
[x: string]: any; // eslint-disable-line
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const defaultDatePickerProps: Omit<DatePickerProps, 'onChange'> = {
|
|
68
|
-
selected: null,
|
|
69
|
-
selectsRange: false,
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
const defaultPopoverProps = {
|
|
73
|
-
align: 'start',
|
|
74
|
-
side: 'bottom',
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
const defaultTextInputProps: Omit<TextInputProps, 'id'> = {
|
|
78
|
-
label: 'Select Date',
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
export const DateInput: FC<DateInputProps> = ({
|
|
82
|
-
datePickerProps,
|
|
83
|
-
textInputProps,
|
|
84
|
-
dateFormat = 'MM/dd/yyyy',
|
|
85
|
-
dateOptions = undefined,
|
|
86
|
-
popoverProps = { ...defaultPopoverProps },
|
|
87
|
-
}) => {
|
|
88
|
-
const { isOpen, handleClose, handleOpen } = useOpenClose();
|
|
89
|
-
|
|
90
|
-
// Internal state for selected date if not controlled
|
|
91
|
-
const isControlled = datePickerProps.selected !== undefined;
|
|
92
|
-
const [internalSelected, setInternalSelected] = useState<Date | null>(
|
|
93
|
-
Array.isArray(datePickerProps.selected)
|
|
94
|
-
? datePickerProps.selected[0] ?? null
|
|
95
|
-
: datePickerProps.selected ?? null
|
|
96
|
-
);
|
|
97
|
-
|
|
98
|
-
// Use controlled or internal state
|
|
99
|
-
const selectedDate = isControlled
|
|
100
|
-
? datePickerProps.selected
|
|
101
|
-
: internalSelected;
|
|
102
|
-
|
|
103
|
-
const mergedDatePickerProps = {
|
|
104
|
-
...defaultDatePickerProps,
|
|
105
|
-
...datePickerProps,
|
|
106
|
-
selected: selectedDate,
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
const mergedPopoverProps = {
|
|
110
|
-
...defaultPopoverProps,
|
|
111
|
-
...popoverProps,
|
|
112
|
-
side: (popoverProps?.side ?? defaultPopoverProps.side) as
|
|
113
|
-
| 'top'
|
|
114
|
-
| 'bottom'
|
|
115
|
-
| 'left'
|
|
116
|
-
| 'right',
|
|
117
|
-
align: (popoverProps?.align ?? defaultPopoverProps.align) as
|
|
118
|
-
| 'start'
|
|
119
|
-
| 'center'
|
|
120
|
-
| 'end',
|
|
121
|
-
onInteractOutside: handleClose,
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
const mergedTextInputProps = {
|
|
125
|
-
...defaultTextInputProps,
|
|
126
|
-
...textInputProps,
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
const getTextInputValue = () => {
|
|
130
|
-
const { selectsRange, startDate, endDate, selected } =
|
|
131
|
-
mergedDatePickerProps;
|
|
132
|
-
// If selectsRange and selected is an array, use it for start/end
|
|
133
|
-
let rangeStart = startDate;
|
|
134
|
-
let rangeEnd = endDate;
|
|
135
|
-
if (selectsRange && Array.isArray(selected)) {
|
|
136
|
-
rangeStart = selected[0] ?? null;
|
|
137
|
-
rangeEnd = selected[1] ?? null;
|
|
138
|
-
}
|
|
139
|
-
const formattedStartDate = rangeStart
|
|
140
|
-
? format(rangeStart, dateFormat, dateOptions)
|
|
141
|
-
: '';
|
|
142
|
-
const formattedEndDate = rangeEnd
|
|
143
|
-
? format(rangeEnd, dateFormat, dateOptions)
|
|
144
|
-
: '';
|
|
145
|
-
const formattedSelectedDate =
|
|
146
|
-
selected && !selectsRange && !Array.isArray(selected)
|
|
147
|
-
? format(selected, dateFormat, dateOptions)
|
|
148
|
-
: '';
|
|
149
|
-
if (selectsRange) {
|
|
150
|
-
return `${formattedStartDate}${
|
|
151
|
-
formattedStartDate || formattedEndDate ? ' - ' : ''
|
|
152
|
-
}${formattedEndDate}`;
|
|
153
|
-
}
|
|
154
|
-
return formattedSelectedDate;
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
const handleDatePickerChange = (
|
|
158
|
-
date: Date | [Date, Date] | null,
|
|
159
|
-
event?: React.SyntheticEvent<any, Event>
|
|
160
|
-
) => {
|
|
161
|
-
if (datePickerProps.onChange) {
|
|
162
|
-
datePickerProps.onChange(date, event);
|
|
163
|
-
}
|
|
164
|
-
if (!isControlled) {
|
|
165
|
-
// If not controlled, update internal state
|
|
166
|
-
if (Array.isArray(date)) {
|
|
167
|
-
setInternalSelected(date[0] ?? null);
|
|
168
|
-
} else {
|
|
169
|
-
setInternalSelected(date);
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
// Close popover when a date is selected (single) or when end date is selected (range)
|
|
173
|
-
if (mergedDatePickerProps.selectsRange) {
|
|
174
|
-
if (Array.isArray(date) && date[0] && date[1]) {
|
|
175
|
-
handleClose();
|
|
176
|
-
}
|
|
177
|
-
} else if (date) {
|
|
178
|
-
handleClose();
|
|
179
|
-
}
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
return (
|
|
183
|
-
<Popover open={isOpen}>
|
|
184
|
-
<PopoverTrigger asChild>
|
|
185
|
-
<TextInput
|
|
186
|
-
id={mergedTextInputProps.id}
|
|
187
|
-
name={mergedTextInputProps.name}
|
|
188
|
-
label={mergedTextInputProps.label}
|
|
189
|
-
value={getTextInputValue()}
|
|
190
|
-
readOnly
|
|
191
|
-
onClick={handleOpen}
|
|
192
|
-
inputProps={{ className: 'text-align-left' }}
|
|
193
|
-
type="text"
|
|
194
|
-
onChange={() =>
|
|
195
|
-
null
|
|
196
|
-
} /* Empty function since we hijack the onChange event */
|
|
197
|
-
{...mergedTextInputProps}
|
|
198
|
-
/>
|
|
199
|
-
</PopoverTrigger>
|
|
200
|
-
<PopoverPortal>
|
|
201
|
-
<PopoverContent {...mergedPopoverProps}>
|
|
202
|
-
<DatePicker
|
|
203
|
-
{...mergedDatePickerProps}
|
|
204
|
-
onChange={handleDatePickerChange}
|
|
205
|
-
selected={selectedDate}
|
|
206
|
-
selectsRange={mergedDatePickerProps.selectsRange}
|
|
207
|
-
/>
|
|
208
|
-
</PopoverContent>
|
|
209
|
-
</PopoverPortal>
|
|
210
|
-
</Popover>
|
|
211
|
-
);
|
|
212
|
-
};
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { Canvas, Meta, ArgTypes } from '@storybook/addon-docs/blocks';
|
|
2
|
-
import { DatePicker } from './DatePicker';
|
|
3
|
-
import * as Stories from './DatePicker.stories';
|
|
4
|
-
|
|
5
|
-
<Meta of={Stories} />
|
|
6
|
-
|
|
7
|
-
# DatePicker
|
|
8
|
-
|
|
9
|
-
The Datepicker lets users select a date by showing them a calendar.
|
|
10
|
-
|
|
11
|
-
It is also used in combination with an input and popover by the [DateInput component](/?path=/docs/components-dateinput-overview--basic-usage).
|
|
12
|
-
|
|
13
|
-
### It can be used for:
|
|
14
|
-
|
|
15
|
-
- selecting a single date
|
|
16
|
-
- selecting a start and end date
|
|
17
|
-
|
|
18
|
-
## Props
|
|
19
|
-
|
|
20
|
-
<ArgTypes of={DatePicker} />
|
|
21
|
-
|
|
22
|
-
## Basic Example
|
|
23
|
-
|
|
24
|
-
<Canvas of={Stories.BasicExample} />
|
|
25
|
-
|
|
26
|
-
## Date Range
|
|
27
|
-
|
|
28
|
-
<Canvas of={Stories.DateRange} />
|
|
29
|
-
|
|
30
|
-
## Min/Max Dates
|
|
31
|
-
|
|
32
|
-
<Canvas of={Stories.MinAndMaxDates} />
|
|
33
|
-
|
|
34
|
-
## Month Picker
|
|
35
|
-
|
|
36
|
-
<Canvas of={Stories.MonthPicker} />
|
|
37
|
-
|
|
38
|
-
## Show Multiple Months
|
|
39
|
-
|
|
40
|
-
<Canvas of={Stories.ShowMultipleMonths} />
|
|
41
|
-
|
|
42
|
-
## With Time Picker
|
|
43
|
-
|
|
44
|
-
<Canvas of={Stories.WithTimePicker} />
|
|
45
|
-
|
|
46
|
-
## Open by default on a specific date
|
|
47
|
-
|
|
48
|
-
<Canvas of={Stories.OpenByDefaultOnASpecificDate} />
|
|
49
|
-
|
|
50
|
-
## With Children
|
|
51
|
-
|
|
52
|
-
<Canvas of={Stories.WithChildren} />
|