@instructure/ui-date-input 9.5.2 → 9.6.1-snapshot-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 +22 -0
- package/es/DateInput2/index.js +89 -59
- package/es/DateInput2/props.js +2 -3
- package/lib/DateInput2/index.js +89 -59
- package/lib/DateInput2/props.js +2 -3
- package/package.json +20 -20
- package/src/DateInput2/README.md +162 -27
- package/src/DateInput2/index.tsx +95 -63
- package/src/DateInput2/props.ts +30 -20
- package/tsconfig.build.tsbuildinfo +1 -1
- package/types/DateInput2/index.d.ts +6 -11
- package/types/DateInput2/index.d.ts.map +1 -1
- package/types/DateInput2/props.d.ts +10 -15
- package/types/DateInput2/props.d.ts.map +1 -1
package/src/DateInput2/README.md
CHANGED
@@ -2,16 +2,53 @@
|
|
2
2
|
describes: DateInput2
|
3
3
|
---
|
4
4
|
|
5
|
-
|
5
|
+
`DateInput2` is an experimental upgrade to the existing [`DateInput`](/#DateInput) component, offering easier configuration, better UX, improved accessibility, and a year picker. While it addresses key limitations of `DateInput`, it's still in the experimental phase, with some missing unit tests and potential (though unlikely) API changes.
|
6
|
+
|
7
|
+
`DateInput` will be deprecated in the future, but for now, developers can start using `DateInput2` and provide feedback.
|
6
8
|
|
7
9
|
### Minimal config
|
8
10
|
|
9
11
|
- ```js
|
10
12
|
class Example extends React.Component {
|
11
|
-
|
13
|
+
initialDate = '2024-09-09T14:00:00.000Z'
|
14
|
+
state = { dateString: this.initialDate, inputValue: '' }
|
12
15
|
|
13
16
|
render() {
|
14
17
|
return (
|
18
|
+
<div>
|
19
|
+
<DateInput2
|
20
|
+
renderLabel="Choose a date"
|
21
|
+
screenReaderLabels={{
|
22
|
+
calendarIcon: 'Calendar',
|
23
|
+
nextMonthButton: 'Next month',
|
24
|
+
prevMonthButton: 'Previous month'
|
25
|
+
}}
|
26
|
+
value={this.state.dateString}
|
27
|
+
width="20rem"
|
28
|
+
onChange={(e, dateString, inputValue) => {
|
29
|
+
this.setState({ dateString, inputValue })
|
30
|
+
}}
|
31
|
+
invalidDateErrorMessage="Invalid date"
|
32
|
+
/>
|
33
|
+
<p>
|
34
|
+
UTC Date String: <code>{this.state.dateString}</code>
|
35
|
+
<br />
|
36
|
+
Input Value: <code>{this.state.inputValue}</code>
|
37
|
+
</p>
|
38
|
+
</div>
|
39
|
+
)
|
40
|
+
}
|
41
|
+
}
|
42
|
+
|
43
|
+
render(<Example />)
|
44
|
+
```
|
45
|
+
|
46
|
+
- ```js
|
47
|
+
const Example = () => {
|
48
|
+
const [dateString, setDateString] = useState('')
|
49
|
+
const [inputValue, setInputValue] = useState('')
|
50
|
+
return (
|
51
|
+
<div>
|
15
52
|
<DateInput2
|
16
53
|
renderLabel="Choose a date"
|
17
54
|
screenReaderLabels={{
|
@@ -19,39 +56,35 @@ This component is an updated version of [`DateInput`](/#DateInput) that's easier
|
|
19
56
|
nextMonthButton: 'Next month',
|
20
57
|
prevMonthButton: 'Previous month'
|
21
58
|
}}
|
22
|
-
value={
|
59
|
+
value={dateString}
|
23
60
|
width="20rem"
|
24
|
-
onChange={(e,
|
61
|
+
onChange={(e, newDateString, newInputValue) => {
|
62
|
+
setDateString(newDateString)
|
63
|
+
setInputValue(newInputValue)
|
64
|
+
}}
|
25
65
|
invalidDateErrorMessage="Invalid date"
|
26
66
|
/>
|
27
|
-
|
28
|
-
|
67
|
+
<p>
|
68
|
+
UTC Date String: <code>{dateString}</code>
|
69
|
+
<br />
|
70
|
+
Input Value: <code>{inputValue}</code>
|
71
|
+
</p>
|
72
|
+
</div>
|
73
|
+
)
|
29
74
|
}
|
30
75
|
|
31
76
|
render(<Example />)
|
32
77
|
```
|
33
78
|
|
34
|
-
|
35
|
-
const Example = () => {
|
36
|
-
const [value, setValue] = useState('')
|
37
|
-
return (
|
38
|
-
<DateInput2
|
39
|
-
renderLabel="Choose a date"
|
40
|
-
screenReaderLabels={{
|
41
|
-
calendarIcon: 'Calendar',
|
42
|
-
nextMonthButton: 'Next month',
|
43
|
-
prevMonthButton: 'Previous month'
|
44
|
-
}}
|
45
|
-
value={value}
|
46
|
-
width="20rem"
|
47
|
-
onChange={(e, value) => setValue(value)}
|
48
|
-
invalidDateErrorMessage="Invalid date"
|
49
|
-
/>
|
50
|
-
)
|
51
|
-
}
|
79
|
+
### Timezones and UTC
|
52
80
|
|
53
|
-
|
54
|
-
|
81
|
+
In the example above you can see that the date is set via the `value` prop and returned from the `onChange` callback. This date is expected to be in UTC timezone. So if a user chooses September 10th 2024 with the timezone 'Europe/Budapest', the `onChange` function will return `2024-09-09T22:00:00.000Z` because Budapest is two hours ahead of UTC.
|
82
|
+
|
83
|
+
Altought it would be nice to use the date picker without timezones and leave the time out alltogether but unfortunately you cannot decouple time from dates since the timezone determines when a day ends and another starts. In certain cases this changes the month or even the year. This can affect how you store and load dates from your database: if you want to set a saved date and that date is already timezone adjusted, you have to set it to utc with your date library of choice.
|
84
|
+
|
85
|
+
### Parsing dates
|
86
|
+
|
87
|
+
When typing a date in the input field instead of using the included picker, the component tries to parse the date as you type it in. To prevent premature parsing (e.g. interpreting `2024` as `2024-01-01T00:00:00.000Z`) parsing only turns on after 10 character. Typed in dates are expected to be in [Date Time String Format](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#date_time_string_format). Any other format are implementation dependant and might differ browser by browser.
|
55
88
|
|
56
89
|
### With year picker
|
57
90
|
|
@@ -113,7 +146,11 @@ This component is an updated version of [`DateInput`](/#DateInput) that's easier
|
|
113
146
|
render(<Example />)
|
114
147
|
```
|
115
148
|
|
116
|
-
###
|
149
|
+
### Date validation
|
150
|
+
|
151
|
+
By default `DateInput2` only does date validation if the `invalidDateErrorMessage` prop is provided. This uses the browser's `Date` object to try and parse the user provided date and displays the error message if it fails. Validation is triggered on the blur event of the input field.
|
152
|
+
|
153
|
+
If you want to do a more complex validation than the above (e.g. only allow a subset of dates) you can use the `onRequestValidateDate` prop to pass a validation function. This function will run on blur or on selecting a date from the picker. The result of the internal validation will be passed to this function. Then you have to set the error messages accordingly. Check the following example for more details:
|
117
154
|
|
118
155
|
```js
|
119
156
|
---
|
@@ -163,3 +200,101 @@ const Example = () => {
|
|
163
200
|
|
164
201
|
render(<Example />)
|
165
202
|
```
|
203
|
+
|
204
|
+
### Date formatting
|
205
|
+
|
206
|
+
The display format of the date value can be set via the `formatDate` property. It will be applied if the user clicks on a date in the date picker or after the blur event from the input field.
|
207
|
+
Something to pay attention to is that the date string passed back in the callback function **is in UTC timezone**.
|
208
|
+
|
209
|
+
```js
|
210
|
+
---
|
211
|
+
type: example
|
212
|
+
---
|
213
|
+
const Example = () => {
|
214
|
+
const [value1, setValue1] = useState('')
|
215
|
+
const [value2, setValue2] = useState('')
|
216
|
+
const [value3, setValue3] = useState('')
|
217
|
+
|
218
|
+
const shortDateFormatFn = (dateString, locale, timezone) => {
|
219
|
+
return new Date(dateString).toLocaleDateString(locale, {
|
220
|
+
month: 'numeric',
|
221
|
+
year: 'numeric',
|
222
|
+
day: 'numeric',
|
223
|
+
timeZone: timezone,
|
224
|
+
})
|
225
|
+
}
|
226
|
+
|
227
|
+
const isoDateFormatFn = (dateString, locale, timezone) => {
|
228
|
+
// this is a simple way to get ISO8601 date in a specific timezone but should not be used in production
|
229
|
+
// please use a proper date library instead like date-fns, luxon or dayjs
|
230
|
+
const localeDate = new Date(dateString).toLocaleDateString('sv', {
|
231
|
+
month: 'numeric',
|
232
|
+
year: 'numeric',
|
233
|
+
day: 'numeric',
|
234
|
+
timeZone: timezone,
|
235
|
+
})
|
236
|
+
|
237
|
+
return localeDate
|
238
|
+
}
|
239
|
+
|
240
|
+
return (
|
241
|
+
<div style={{display: 'flex', flexDirection: 'column', gap: '1.5rem'}}>
|
242
|
+
<DateInput2
|
243
|
+
renderLabel="Default format"
|
244
|
+
screenReaderLabels={{
|
245
|
+
calendarIcon: 'Calendar',
|
246
|
+
nextMonthButton: 'Next month',
|
247
|
+
prevMonthButton: 'Previous month'
|
248
|
+
}}
|
249
|
+
isInline
|
250
|
+
width="20rem"
|
251
|
+
value={value1}
|
252
|
+
onChange={(e, value) => setValue1(value)}
|
253
|
+
withYearPicker={{
|
254
|
+
screenReaderLabel: 'Year picker',
|
255
|
+
startYear: 1900,
|
256
|
+
endYear: 2024
|
257
|
+
}}
|
258
|
+
/>
|
259
|
+
<DateInput2
|
260
|
+
renderLabel="Short format in current locale"
|
261
|
+
screenReaderLabels={{
|
262
|
+
calendarIcon: 'Calendar',
|
263
|
+
nextMonthButton: 'Next month',
|
264
|
+
prevMonthButton: 'Previous month'
|
265
|
+
}}
|
266
|
+
isInline
|
267
|
+
width="20rem"
|
268
|
+
value={value2}
|
269
|
+
onChange={(e, value) => setValue2(value)}
|
270
|
+
formatDate={shortDateFormatFn}
|
271
|
+
withYearPicker={{
|
272
|
+
screenReaderLabel: 'Year picker',
|
273
|
+
startYear: 1900,
|
274
|
+
endYear: 2024
|
275
|
+
}}
|
276
|
+
/>
|
277
|
+
<DateInput2
|
278
|
+
renderLabel="ISO8601"
|
279
|
+
screenReaderLabels={{
|
280
|
+
calendarIcon: 'Calendar',
|
281
|
+
nextMonthButton: 'Next month',
|
282
|
+
prevMonthButton: 'Previous month'
|
283
|
+
}}
|
284
|
+
isInline
|
285
|
+
width="20rem"
|
286
|
+
value={value3}
|
287
|
+
onChange={(e, value) => setValue3(value)}
|
288
|
+
formatDate={isoDateFormatFn}
|
289
|
+
withYearPicker={{
|
290
|
+
screenReaderLabel: 'Year picker',
|
291
|
+
startYear: 1900,
|
292
|
+
endYear: 2024
|
293
|
+
}}
|
294
|
+
/>
|
295
|
+
</div>
|
296
|
+
)
|
297
|
+
}
|
298
|
+
|
299
|
+
render(<Example />)
|
300
|
+
```
|
package/src/DateInput2/index.tsx
CHANGED
@@ -44,16 +44,55 @@ import type { DateInput2Props } from './props'
|
|
44
44
|
import type { FormMessage } from '@instructure/ui-form-field'
|
45
45
|
import type { Moment } from '@instructure/ui-i18n'
|
46
46
|
|
47
|
-
|
47
|
+
/*
|
48
|
+
* Tries parsing a date in a given timezone, if it's not possible, returns an empty string
|
49
|
+
* If parsing is successful an ISO formatted datetime string is returned in UTC timezone
|
50
|
+
*/
|
51
|
+
function timezoneDateToUtc(dateString: string, timezone: string): string {
|
52
|
+
// Don't try to parse short dateString, they are incomplete
|
53
|
+
if (dateString.length < 10) {
|
54
|
+
return ''
|
55
|
+
}
|
56
|
+
|
57
|
+
// Create a Date object from the input date string
|
48
58
|
const date = new Date(dateString)
|
49
|
-
|
50
|
-
|
59
|
+
|
60
|
+
// Check if the date is valid
|
61
|
+
if (isNaN(date.getTime())) {
|
62
|
+
return ''
|
63
|
+
}
|
64
|
+
|
65
|
+
// snippet from https://stackoverflow.com/a/57842203
|
66
|
+
// but it might need to be improved:
|
67
|
+
// "This produces incorrect datetimes for several hours surrounding daylight saving times if the
|
68
|
+
// computer running the code is in a zone that doesn't obey the same daylight saving shifts as the target zone."
|
69
|
+
const utcDate = new Date(date.toLocaleString('en-US', { timeZone: 'UTC' }))
|
70
|
+
const tzDate = new Date(date.toLocaleString('en-US', { timeZone: timezone }))
|
71
|
+
const offset = utcDate.getTime() - tzDate.getTime()
|
72
|
+
const newDate = new Date(date.getTime() + offset)
|
73
|
+
|
74
|
+
return newDate.toISOString()
|
75
|
+
}
|
76
|
+
|
77
|
+
function defaultDateFormatter(
|
78
|
+
dateString: string,
|
79
|
+
locale: string,
|
80
|
+
timezone: string
|
81
|
+
) {
|
82
|
+
return new Date(dateString).toLocaleDateString(locale, {
|
83
|
+
month: 'long',
|
84
|
+
year: 'numeric',
|
85
|
+
day: 'numeric',
|
86
|
+
timeZone: timezone
|
87
|
+
})
|
51
88
|
}
|
52
89
|
|
53
90
|
/**
|
54
91
|
---
|
55
92
|
category: components
|
56
93
|
---
|
94
|
+
|
95
|
+
@module experimental
|
57
96
|
**/
|
58
97
|
const DateInput2 = ({
|
59
98
|
renderLabel,
|
@@ -73,31 +112,52 @@ const DateInput2 = ({
|
|
73
112
|
locale,
|
74
113
|
timezone,
|
75
114
|
placeholder,
|
115
|
+
formatDate = defaultDateFormatter,
|
116
|
+
// margin, TODO enable this prop
|
76
117
|
...rest
|
77
118
|
}: DateInput2Props) => {
|
78
|
-
const
|
119
|
+
const localeContext = useContext(ApplyLocaleContext)
|
120
|
+
|
121
|
+
const getLocale = () => {
|
122
|
+
if (locale) {
|
123
|
+
return locale
|
124
|
+
} else if (localeContext.locale) {
|
125
|
+
return localeContext.locale
|
126
|
+
}
|
127
|
+
// default to the system's locale
|
128
|
+
return Locale.browserLocale()
|
129
|
+
}
|
130
|
+
|
131
|
+
const getTimezone = () => {
|
132
|
+
if (timezone) {
|
133
|
+
return timezone
|
134
|
+
} else if (localeContext.timezone) {
|
135
|
+
return localeContext.timezone
|
136
|
+
}
|
137
|
+
// default to the system's timezone
|
138
|
+
return Intl.DateTimeFormat().resolvedOptions().timeZone
|
139
|
+
}
|
140
|
+
|
141
|
+
const [inputValue, setInputValue] = useState<string>(
|
142
|
+
value ? formatDate(value, getLocale(), getTimezone()) : ''
|
143
|
+
)
|
79
144
|
const [inputMessages, setInputMessages] = useState<FormMessage[]>(
|
80
145
|
messages || []
|
81
146
|
)
|
82
147
|
const [showPopover, setShowPopover] = useState<boolean>(false)
|
83
|
-
const localeContext = useContext(ApplyLocaleContext)
|
84
|
-
|
85
|
-
useEffect(() => {
|
86
|
-
// when `value` is changed, validation runs again and removes the error message if validation passes
|
87
|
-
// but it's NOT adding error message if validation fails for better UX
|
88
|
-
validateInput(true)
|
89
|
-
}, [value])
|
90
148
|
|
91
149
|
useEffect(() => {
|
92
150
|
setInputMessages(messages || [])
|
93
151
|
}, [messages])
|
94
152
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
153
|
+
useEffect(() => {
|
154
|
+
validateInput(true)
|
155
|
+
}, [inputValue])
|
156
|
+
|
157
|
+
const handleInputChange = (e: SyntheticEvent, newValue: string) => {
|
158
|
+
setInputValue(newValue)
|
159
|
+
const parsedInput = timezoneDateToUtc(newValue, getTimezone())
|
160
|
+
onChange?.(e, parsedInput, newValue)
|
101
161
|
}
|
102
162
|
|
103
163
|
const handleDateSelected = (
|
@@ -105,22 +165,17 @@ const DateInput2 = ({
|
|
105
165
|
_momentDate: Moment,
|
106
166
|
e: SyntheticEvent
|
107
167
|
) => {
|
108
|
-
const formattedDate =
|
109
|
-
|
110
|
-
year: 'numeric',
|
111
|
-
day: 'numeric',
|
112
|
-
timeZone: getTimezone()
|
113
|
-
})
|
114
|
-
handleInputChange(e, formattedDate)
|
115
|
-
setSelectedDate(dateString)
|
168
|
+
const formattedDate = formatDate(dateString, getLocale(), getTimezone())
|
169
|
+
setInputValue(formattedDate)
|
116
170
|
setShowPopover(false)
|
171
|
+
onChange?.(e, dateString, formattedDate)
|
117
172
|
onRequestValidateDate?.(dateString, true)
|
118
173
|
}
|
119
174
|
|
120
175
|
// onlyRemoveError is used to remove the error msg immediately when the user inputs a valid date (and don't wait for blur event)
|
121
176
|
const validateInput = (onlyRemoveError = false): boolean => {
|
122
177
|
// don't validate empty input
|
123
|
-
if (!
|
178
|
+
if (!inputValue || timezoneDateToUtc(inputValue, getTimezone()) || value) {
|
124
179
|
setInputMessages(messages || [])
|
125
180
|
return true
|
126
181
|
}
|
@@ -141,51 +196,28 @@ const DateInput2 = ({
|
|
141
196
|
return false
|
142
197
|
}
|
143
198
|
|
144
|
-
const getLocale = () => {
|
145
|
-
if (locale) {
|
146
|
-
return locale
|
147
|
-
} else if (localeContext.locale) {
|
148
|
-
return localeContext.locale
|
149
|
-
}
|
150
|
-
return Locale.browserLocale()
|
151
|
-
}
|
152
|
-
|
153
|
-
const getTimezone = () => {
|
154
|
-
if (timezone) {
|
155
|
-
return timezone
|
156
|
-
} else if (localeContext.timezone) {
|
157
|
-
return localeContext.timezone
|
158
|
-
}
|
159
|
-
// default to the system's timezone
|
160
|
-
return Intl.DateTimeFormat().resolvedOptions().timeZone
|
161
|
-
}
|
162
|
-
|
163
199
|
const handleBlur = (e: SyntheticEvent) => {
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
year: 'numeric',
|
171
|
-
day: 'numeric',
|
172
|
-
timeZone: getTimezone()
|
173
|
-
}
|
174
|
-
)
|
175
|
-
handleInputChange(e, formattedDate)
|
200
|
+
if (value) {
|
201
|
+
const formattedDate = formatDate(value, getLocale(), getTimezone())
|
202
|
+
if (formattedDate !== inputValue) {
|
203
|
+
setInputValue(formattedDate)
|
204
|
+
onChange?.(e, value, formattedDate)
|
205
|
+
}
|
176
206
|
}
|
177
|
-
|
207
|
+
validateInput(false)
|
208
|
+
onRequestValidateDate?.(value, !!value)
|
178
209
|
onBlur?.(e)
|
179
210
|
}
|
180
211
|
|
181
212
|
return (
|
182
213
|
<TextInput
|
183
214
|
{...passthroughProps(rest)}
|
215
|
+
// margin={'large'} TODO add this prop to TextInput
|
184
216
|
renderLabel={renderLabel}
|
185
217
|
onChange={handleInputChange}
|
186
218
|
onBlur={handleBlur}
|
187
219
|
isRequired={isRequired}
|
188
|
-
value={
|
220
|
+
value={inputValue}
|
189
221
|
placeholder={placeholder}
|
190
222
|
width={width}
|
191
223
|
size={size}
|
@@ -217,10 +249,10 @@ const DateInput2 = ({
|
|
217
249
|
<Calendar
|
218
250
|
withYearPicker={withYearPicker}
|
219
251
|
onDateSelected={handleDateSelected}
|
220
|
-
selectedDate={
|
221
|
-
visibleMonth={
|
222
|
-
locale={
|
223
|
-
timezone={
|
252
|
+
selectedDate={value}
|
253
|
+
visibleMonth={value}
|
254
|
+
locale={getLocale()}
|
255
|
+
timezone={getTimezone()}
|
224
256
|
role="listbox"
|
225
257
|
renderNextMonthButton={
|
226
258
|
<IconButton
|
package/src/DateInput2/props.ts
CHANGED
@@ -28,7 +28,11 @@ import type { SyntheticEvent, InputHTMLAttributes } from 'react'
|
|
28
28
|
import { controllable } from '@instructure/ui-prop-types'
|
29
29
|
import { FormPropTypes } from '@instructure/ui-form-field'
|
30
30
|
import type { FormMessage } from '@instructure/ui-form-field'
|
31
|
-
import type {
|
31
|
+
import type {
|
32
|
+
OtherHTMLAttributes,
|
33
|
+
Renderable,
|
34
|
+
PropValidators
|
35
|
+
} from '@instructure/shared-types'
|
32
36
|
|
33
37
|
type DateInput2OwnProps = {
|
34
38
|
/**
|
@@ -41,9 +45,9 @@ type DateInput2OwnProps = {
|
|
41
45
|
nextMonthButton: string
|
42
46
|
}
|
43
47
|
/**
|
44
|
-
* Specifies the input value.
|
48
|
+
* Specifies the input value *before* formatting. The `formatDate` will be applied to it before displaying. Should be a valid, parsable date.
|
45
49
|
*/
|
46
|
-
value?: string
|
50
|
+
value?: string
|
47
51
|
/**
|
48
52
|
* Specifies the input size.
|
49
53
|
*/
|
@@ -56,7 +60,11 @@ type DateInput2OwnProps = {
|
|
56
60
|
/**
|
57
61
|
* Callback fired when the input changes.
|
58
62
|
*/
|
59
|
-
onChange?: (
|
63
|
+
onChange?: (
|
64
|
+
event: React.SyntheticEvent,
|
65
|
+
isoDateString: string,
|
66
|
+
formattedValue: string
|
67
|
+
) => void
|
60
68
|
/**
|
61
69
|
* Callback executed when the input fires a blur event.
|
62
70
|
*/
|
@@ -91,21 +99,12 @@ type DateInput2OwnProps = {
|
|
91
99
|
*/
|
92
100
|
messages?: FormMessage[]
|
93
101
|
/**
|
94
|
-
* Callback fired
|
95
|
-
|
96
|
-
|
97
|
-
/**
|
98
|
-
* Callback fired requesting the calendar be hidden.
|
99
|
-
*/
|
100
|
-
onRequestHideCalendar?: (event: SyntheticEvent) => void
|
101
|
-
/**
|
102
|
-
* Callback fired when the input is blurred. Feedback should be provided
|
103
|
-
* to the user when this function is called if the selected date or input
|
104
|
-
* value is invalid. The component has an internal check whether the date can
|
105
|
-
* be parsed to a valid date.
|
102
|
+
* Callback fired when the input is blurred or a date is selected from the calendar.
|
103
|
+
* Feedback should be provided to the user when this function is called if the selected date or input
|
104
|
+
* value is invalid. The component has an internal check whether the date can be parsed to a valid date.
|
106
105
|
*/
|
107
106
|
onRequestValidateDate?: (
|
108
|
-
|
107
|
+
isoDateString?: string,
|
109
108
|
internalValidationPassed?: boolean
|
110
109
|
) => void | FormMessage[]
|
111
110
|
/**
|
@@ -157,6 +156,18 @@ type DateInput2OwnProps = {
|
|
157
156
|
startYear: number
|
158
157
|
endYear: number
|
159
158
|
}
|
159
|
+
|
160
|
+
/**
|
161
|
+
* Formatting function for how the date should be displayed inside the input field. It will be applied if the user clicks on a date in the date picker of after blur event from the input field.
|
162
|
+
*/
|
163
|
+
formatDate?: (isoDate: string, locale: string, timezone: string) => string
|
164
|
+
|
165
|
+
/**
|
166
|
+
* Valid values are `0`, `none`, `auto`, `xxx-small`, `xx-small`, `x-small`,
|
167
|
+
* `small`, `medium`, `large`, `x-large`, `xx-large`. Apply these values via
|
168
|
+
* familiar CSS-like shorthand. For example: `margin="small auto large"`.
|
169
|
+
*/
|
170
|
+
// margin?: Spacing TODO enable this prop
|
160
171
|
}
|
161
172
|
|
162
173
|
type PropKeys = keyof DateInput2OwnProps
|
@@ -180,8 +191,6 @@ const propTypes: PropValidators<PropKeys> = {
|
|
180
191
|
isInline: PropTypes.bool,
|
181
192
|
width: PropTypes.string,
|
182
193
|
messages: PropTypes.arrayOf(FormPropTypes.message),
|
183
|
-
onRequestShowCalendar: PropTypes.func,
|
184
|
-
onRequestHideCalendar: PropTypes.func,
|
185
194
|
onRequestValidateDate: PropTypes.func,
|
186
195
|
invalidDateErrorMessage: PropTypes.oneOfType([
|
187
196
|
PropTypes.func,
|
@@ -189,7 +198,8 @@ const propTypes: PropValidators<PropKeys> = {
|
|
189
198
|
]),
|
190
199
|
locale: PropTypes.string,
|
191
200
|
timezone: PropTypes.string,
|
192
|
-
withYearPicker: PropTypes.object
|
201
|
+
withYearPicker: PropTypes.object,
|
202
|
+
formatDate: PropTypes.func
|
193
203
|
}
|
194
204
|
|
195
205
|
export type { DateInput2Props }
|