@instructure/ui-date-input 9.6.0 → 9.6.1-pr-snapshot-1726659472372

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
@@ -3,6 +3,17 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [9.6.1-pr-snapshot-1726659472372](https://github.com/instructure/instructure-ui/compare/v9.6.0...v9.6.1-pr-snapshot-1726659472372) (2024-09-18)
7
+
8
+
9
+ ### Features
10
+
11
+ * **ui-date-input:** improve DateInput2 api, extend docs ([27bc27f](https://github.com/instructure/instructure-ui/commit/27bc27f8a5e18cf3cabee8b5ea18f75629728ab6))
12
+
13
+
14
+
15
+
16
+
6
17
  # [9.6.0](https://github.com/instructure/instructure-ui/compare/v9.5.2...v9.6.0) (2024-08-14)
7
18
 
8
19
 
@@ -35,30 +35,85 @@ import { passthroughProps } from '@instructure/ui-react-utils';
35
35
  import { ApplyLocaleContext, Locale } from '@instructure/ui-i18n';
36
36
  import { jsx } from '@instructure/emotion';
37
37
  import { propTypes } from './props';
38
- function parseDate(dateString) {
39
- const date = new Date(dateString);
40
- return isNaN(date.getTime()) ? '' : date.toISOString();
41
- }
42
- function defaultDateFormatter(dateString, locale, timezone) {
43
- return new Date(dateString).toLocaleDateString(locale, {
44
- month: 'long',
45
- year: 'numeric',
46
- day: 'numeric',
47
- timeZone: timezone
38
+ function parseLocaleDate(dateString = '', locale, timeZone) {
39
+ // This function may seem complicated but it basically does one thing:
40
+ // Given a dateString, a locale and a timeZone. The dateString is assumed to be formatted according
41
+ // to the locale. So if the locale is `en-us` the dateString is expected to be in the format of M/D/YYYY.
42
+ // The dateString is also assumed to be in the given timeZone, so "1/1/2020" in "America/Los_Angeles" timezone is
43
+ // expected to be "2020-01-01T08:00:00.000Z" in UTC time.
44
+ // This function tries to parse the dateString taking these variables into account and return a javascript Date object
45
+ // that is adjusted to be in UTC.
46
+
47
+ // Split string on '.', whitespace, '/', ',' or '-' using regex: /[.\s/.-]+/.
48
+ // The '+' allows splitting on consecutive delimiters.
49
+ // `.filter(Boolean)` is needed because some locales have a delimeter at the end (e.g.: "hu-hu")
50
+ const splitDate = dateString.split(/[,.\s/.-]+/).filter(Boolean);
51
+
52
+ // create a locale formatted new date to later extract the order and delimeter information
53
+ const localeDate = new Intl.DateTimeFormat(locale).formatToParts(new Date());
54
+ let index = 0;
55
+ let day, month, year;
56
+ localeDate.forEach(part => {
57
+ if (part.type === 'month') {
58
+ month = parseInt(splitDate[index], 10);
59
+ index++;
60
+ } else if (part.type === 'day') {
61
+ day = parseInt(splitDate[index], 10);
62
+ index++;
63
+ } else if (part.type === 'year') {
64
+ year = parseInt(splitDate[index], 10);
65
+ index++;
66
+ }
48
67
  });
68
+
69
+ // sensible year limitations
70
+ if (!year || !month || !day || year < 1000 || year > 9999) return null;
71
+
72
+ // create utc date from year, month (zero indexed) and day
73
+ const date = new Date(Date.UTC(year, month - 1, day));
74
+
75
+ // Format date string in the provided timezone
76
+ const parts = new Intl.DateTimeFormat('en-US', {
77
+ timeZone,
78
+ year: 'numeric',
79
+ month: '2-digit',
80
+ day: '2-digit',
81
+ hour: '2-digit',
82
+ minute: '2-digit',
83
+ second: '2-digit',
84
+ hour12: false
85
+ }).formatToParts(date);
86
+
87
+ // Extract the date and time parts from the formatted string
88
+ const dateStringInTimezone = parts.reduce((acc, part) => {
89
+ return part.type === 'literal' ? acc : {
90
+ ...acc,
91
+ [part.type]: part.value
92
+ };
93
+ }, {});
94
+
95
+ // Create a date string in the format 'YYYY-MM-DDTHH:mm:ss'
96
+ const dateInTimezone = `${dateStringInTimezone.year}-${dateStringInTimezone.month}-${dateStringInTimezone.day}T${dateStringInTimezone.hour}:${dateStringInTimezone.minute}:${dateStringInTimezone.second}`;
97
+
98
+ // Calculate time difference for timezone offset
99
+ const timeDiff = new Date(dateInTimezone + 'Z').getTime() - date.getTime();
100
+ const newTime = new Date(date.getTime() - timeDiff);
101
+ // Return the UTC Date corresponding to the time in the specified timezone
102
+ return newTime;
49
103
  }
50
104
 
51
105
  /**
52
106
  ---
53
107
  category: components
54
108
  ---
109
+
110
+ @module experimental
55
111
  **/
56
112
  const DateInput2 = ({
57
113
  renderLabel,
58
114
  screenReaderLabels,
59
115
  isRequired = false,
60
116
  interaction = 'enabled',
61
- size = 'medium',
62
117
  isInline = false,
63
118
  value,
64
119
  messages,
@@ -66,77 +121,23 @@ const DateInput2 = ({
66
121
  onChange,
67
122
  onBlur,
68
123
  withYearPicker,
69
- onRequestValidateDate,
70
124
  invalidDateErrorMessage,
71
125
  locale,
72
126
  timezone,
73
127
  placeholder,
74
- formatDate = defaultDateFormatter,
128
+ dateFormat,
129
+ onRequestValidateDate,
75
130
  // margin, TODO enable this prop
76
131
  ...rest
77
132
  }) => {
78
- const _useState = useState(''),
79
- _useState2 = _slicedToArray(_useState, 2),
80
- selectedDate = _useState2[0],
81
- setSelectedDate = _useState2[1];
82
- const _useState3 = useState(messages || []),
83
- _useState4 = _slicedToArray(_useState3, 2),
84
- inputMessages = _useState4[0],
85
- setInputMessages = _useState4[1];
86
- const _useState5 = useState(false),
87
- _useState6 = _slicedToArray(_useState5, 2),
88
- showPopover = _useState6[0],
89
- setShowPopover = _useState6[1];
90
133
  const localeContext = useContext(ApplyLocaleContext);
91
- useEffect(() => {
92
- // when `value` is changed, validation removes the error message if passes
93
- // but it's NOT adding error message if validation fails for better UX
94
- validateInput(true);
95
- }, [value]);
96
- useEffect(() => {
97
- setInputMessages(messages || []);
98
- }, [messages]);
99
- useEffect(() => {
100
- setSelectedDate(parseDate(value || ''));
101
- }, []);
102
- const handleInputChange = (e, newValue, parsedDate = '') => {
103
- // blur event formats the input which shouldn't trigger parsing
104
- if (e.type !== 'blur') {
105
- setSelectedDate(parseDate(newValue));
106
- }
107
- onChange === null || onChange === void 0 ? void 0 : onChange(e, newValue, parsedDate);
108
- };
109
- const handleDateSelected = (dateString, _momentDate, e) => {
110
- const formattedDate = formatDate(dateString, getLocale(), getTimezone());
111
- const parsedDate = parseDate(dateString);
112
- setSelectedDate(parsedDate);
113
- handleInputChange(e, formattedDate, parsedDate);
114
- setShowPopover(false);
115
- onRequestValidateDate === null || onRequestValidateDate === void 0 ? void 0 : onRequestValidateDate(dateString, true);
116
- };
117
-
118
- // onlyRemoveError is used to remove the error msg immediately when the user inputs a valid date (and don't wait for blur event)
119
- const validateInput = (onlyRemoveError = false) => {
120
- // don't validate empty input
121
- if (!value || parseDate(value) || selectedDate) {
122
- setInputMessages(messages || []);
123
- return true;
124
- }
125
- // only show error if there is no user provided validation callback
126
- if (!onlyRemoveError && typeof invalidDateErrorMessage === 'string' && !onRequestValidateDate) {
127
- setInputMessages([{
128
- type: 'error',
129
- text: invalidDateErrorMessage
130
- }]);
131
- }
132
- return false;
133
- };
134
134
  const getLocale = () => {
135
135
  if (locale) {
136
136
  return locale;
137
137
  } else if (localeContext.locale) {
138
138
  return localeContext.locale;
139
139
  }
140
+ // default to the system's locale
140
141
  return Locale.browserLocale();
141
142
  };
142
143
  const getTimezone = () => {
@@ -148,15 +149,84 @@ const DateInput2 = ({
148
149
  // default to the system's timezone
149
150
  return Intl.DateTimeFormat().resolvedOptions().timeZone;
150
151
  };
152
+ const _useState = useState(messages || []),
153
+ _useState2 = _slicedToArray(_useState, 2),
154
+ inputMessages = _useState2[0],
155
+ setInputMessages = _useState2[1];
156
+ const _useState3 = useState(false),
157
+ _useState4 = _slicedToArray(_useState3, 2),
158
+ showPopover = _useState4[0],
159
+ setShowPopover = _useState4[1];
160
+ useEffect(() => {
161
+ setInputMessages(messages || []);
162
+ }, [messages]);
163
+ useEffect(() => {
164
+ const _parseDate = parseDate(value),
165
+ _parseDate2 = _slicedToArray(_parseDate, 2),
166
+ utcIsoDate = _parseDate2[1];
167
+ // clear error messages if date becomes valid
168
+ if (utcIsoDate || !value) {
169
+ setInputMessages(messages || []);
170
+ }
171
+ }, [value]);
172
+ const parseDate = (dateString = '') => {
173
+ let date = null;
174
+ if (dateFormat) {
175
+ if (typeof dateFormat === 'string') {
176
+ // use dateFormat instead of the user locale
177
+ date = parseLocaleDate(dateString, dateFormat, getTimezone());
178
+ } else if (dateFormat.parser) {
179
+ date = dateFormat.parser(dateString);
180
+ }
181
+ } else {
182
+ // no dateFormat prop passed, use locale for formatting
183
+ date = parseLocaleDate(dateString, getLocale(), getTimezone());
184
+ }
185
+ return date ? [formatDate(date), date.toISOString()] : ['', ''];
186
+ };
187
+ const formatDate = date => {
188
+ // use formatter function if provided
189
+ if (typeof dateFormat !== 'string' && dateFormat !== null && dateFormat !== void 0 && dateFormat.formatter) {
190
+ return dateFormat.formatter(date);
191
+ }
192
+ // if dateFormat set to a locale, use that, otherwise default to the user's locale
193
+ return date.toLocaleDateString(typeof dateFormat === 'string' ? dateFormat : getLocale(), {
194
+ timeZone: getTimezone(),
195
+ calendar: 'gregory',
196
+ numberingSystem: 'latn'
197
+ });
198
+ };
199
+ const handleInputChange = (e, newValue) => {
200
+ const _parseDate3 = parseDate(newValue),
201
+ _parseDate4 = _slicedToArray(_parseDate3, 2),
202
+ utcIsoDate = _parseDate4[1];
203
+ onChange === null || onChange === void 0 ? void 0 : onChange(e, newValue, utcIsoDate);
204
+ };
205
+ const handleDateSelected = (dateString, _momentDate, e) => {
206
+ setShowPopover(false);
207
+ const newValue = formatDate(new Date(dateString));
208
+ onChange === null || onChange === void 0 ? void 0 : onChange(e, newValue, dateString);
209
+ onRequestValidateDate === null || onRequestValidateDate === void 0 ? void 0 : onRequestValidateDate(e, newValue, dateString);
210
+ };
151
211
  const handleBlur = e => {
152
- const isInputValid = validateInput(false);
153
- if (isInputValid && selectedDate) {
154
- const formattedDate = formatDate(selectedDate, getLocale(), getTimezone());
155
- handleInputChange(e, formattedDate, selectedDate);
212
+ const _parseDate5 = parseDate(value),
213
+ _parseDate6 = _slicedToArray(_parseDate5, 2),
214
+ localeDate = _parseDate6[0],
215
+ utcIsoDate = _parseDate6[1];
216
+ if (localeDate) {
217
+ if (localeDate !== value) {
218
+ onChange === null || onChange === void 0 ? void 0 : onChange(e, localeDate, utcIsoDate);
219
+ }
220
+ } else if (value && invalidDateErrorMessage) {
221
+ setInputMessages([{
222
+ type: 'error',
223
+ text: invalidDateErrorMessage
224
+ }]);
156
225
  }
157
- onRequestValidateDate === null || onRequestValidateDate === void 0 ? void 0 : onRequestValidateDate(value, isInputValid);
158
- onBlur === null || onBlur === void 0 ? void 0 : onBlur(e);
226
+ onRequestValidateDate === null || onRequestValidateDate === void 0 ? void 0 : onRequestValidateDate(e, value || '', utcIsoDate);
227
+ onBlur === null || onBlur === void 0 ? void 0 : onBlur(e, value || '', utcIsoDate);
159
228
  };
229
+ const selectedDate = parseDate(value)[1];
160
230
  return jsx(TextInput, Object.assign({}, passthroughProps(rest), {
161
231
  // margin={'large'} TODO add this prop to TextInput
162
232
  renderLabel: renderLabel,
@@ -166,7 +236,6 @@ const DateInput2 = ({
166
236
  value: value,
167
237
  placeholder: placeholder,
168
238
  width: width,
169
- size: size,
170
239
  display: isInline ? 'inline-block' : 'block',
171
240
  messages: inputMessages,
172
241
  interaction: interaction,
@@ -176,7 +245,6 @@ const DateInput2 = ({
176
245
  withBorder: false,
177
246
  screenReaderLabel: screenReaderLabels.calendarIcon,
178
247
  shape: "circle",
179
- size: size,
180
248
  interaction: interaction
181
249
  }, _IconCalendarMonthLin || (_IconCalendarMonthLin = jsx(IconCalendarMonthLine, null))),
182
250
  isShowingContent: showPopover,
@@ -29,7 +29,6 @@ const propTypes = {
29
29
  renderLabel: PropTypes.oneOfType([PropTypes.node, PropTypes.func]).isRequired,
30
30
  screenReaderLabels: PropTypes.object.isRequired,
31
31
  value: controllable(PropTypes.string),
32
- size: PropTypes.oneOf(['small', 'medium', 'large']),
33
32
  placeholder: PropTypes.string,
34
33
  onChange: PropTypes.func,
35
34
  onBlur: PropTypes.func,
@@ -38,13 +37,11 @@ const propTypes = {
38
37
  isInline: PropTypes.bool,
39
38
  width: PropTypes.string,
40
39
  messages: PropTypes.arrayOf(FormPropTypes.message),
41
- onRequestShowCalendar: PropTypes.func,
42
- onRequestHideCalendar: PropTypes.func,
43
- onRequestValidateDate: PropTypes.func,
44
40
  invalidDateErrorMessage: PropTypes.oneOfType([PropTypes.func, PropTypes.string]),
45
41
  locale: PropTypes.string,
46
42
  timezone: PropTypes.string,
47
43
  withYearPicker: PropTypes.object,
48
- formatDate: PropTypes.func
44
+ dateFormat: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
45
+ onRequestValidateDate: PropTypes.func
49
46
  };
50
47
  export { propTypes };
@@ -44,30 +44,85 @@ var _IconCalendarMonthLin, _IconArrowOpenEndSoli, _IconArrowOpenStartSo;
44
44
  * SOFTWARE.
45
45
  */
46
46
  /** @jsx jsx */
47
- function parseDate(dateString) {
48
- const date = new Date(dateString);
49
- return isNaN(date.getTime()) ? '' : date.toISOString();
50
- }
51
- function defaultDateFormatter(dateString, locale, timezone) {
52
- return new Date(dateString).toLocaleDateString(locale, {
53
- month: 'long',
54
- year: 'numeric',
55
- day: 'numeric',
56
- timeZone: timezone
47
+ function parseLocaleDate(dateString = '', locale, timeZone) {
48
+ // This function may seem complicated but it basically does one thing:
49
+ // Given a dateString, a locale and a timeZone. The dateString is assumed to be formatted according
50
+ // to the locale. So if the locale is `en-us` the dateString is expected to be in the format of M/D/YYYY.
51
+ // The dateString is also assumed to be in the given timeZone, so "1/1/2020" in "America/Los_Angeles" timezone is
52
+ // expected to be "2020-01-01T08:00:00.000Z" in UTC time.
53
+ // This function tries to parse the dateString taking these variables into account and return a javascript Date object
54
+ // that is adjusted to be in UTC.
55
+
56
+ // Split string on '.', whitespace, '/', ',' or '-' using regex: /[.\s/.-]+/.
57
+ // The '+' allows splitting on consecutive delimiters.
58
+ // `.filter(Boolean)` is needed because some locales have a delimeter at the end (e.g.: "hu-hu")
59
+ const splitDate = dateString.split(/[,.\s/.-]+/).filter(Boolean);
60
+
61
+ // create a locale formatted new date to later extract the order and delimeter information
62
+ const localeDate = new Intl.DateTimeFormat(locale).formatToParts(new Date());
63
+ let index = 0;
64
+ let day, month, year;
65
+ localeDate.forEach(part => {
66
+ if (part.type === 'month') {
67
+ month = parseInt(splitDate[index], 10);
68
+ index++;
69
+ } else if (part.type === 'day') {
70
+ day = parseInt(splitDate[index], 10);
71
+ index++;
72
+ } else if (part.type === 'year') {
73
+ year = parseInt(splitDate[index], 10);
74
+ index++;
75
+ }
57
76
  });
77
+
78
+ // sensible year limitations
79
+ if (!year || !month || !day || year < 1000 || year > 9999) return null;
80
+
81
+ // create utc date from year, month (zero indexed) and day
82
+ const date = new Date(Date.UTC(year, month - 1, day));
83
+
84
+ // Format date string in the provided timezone
85
+ const parts = new Intl.DateTimeFormat('en-US', {
86
+ timeZone,
87
+ year: 'numeric',
88
+ month: '2-digit',
89
+ day: '2-digit',
90
+ hour: '2-digit',
91
+ minute: '2-digit',
92
+ second: '2-digit',
93
+ hour12: false
94
+ }).formatToParts(date);
95
+
96
+ // Extract the date and time parts from the formatted string
97
+ const dateStringInTimezone = parts.reduce((acc, part) => {
98
+ return part.type === 'literal' ? acc : {
99
+ ...acc,
100
+ [part.type]: part.value
101
+ };
102
+ }, {});
103
+
104
+ // Create a date string in the format 'YYYY-MM-DDTHH:mm:ss'
105
+ const dateInTimezone = `${dateStringInTimezone.year}-${dateStringInTimezone.month}-${dateStringInTimezone.day}T${dateStringInTimezone.hour}:${dateStringInTimezone.minute}:${dateStringInTimezone.second}`;
106
+
107
+ // Calculate time difference for timezone offset
108
+ const timeDiff = new Date(dateInTimezone + 'Z').getTime() - date.getTime();
109
+ const newTime = new Date(date.getTime() - timeDiff);
110
+ // Return the UTC Date corresponding to the time in the specified timezone
111
+ return newTime;
58
112
  }
59
113
 
60
114
  /**
61
115
  ---
62
116
  category: components
63
117
  ---
118
+
119
+ @module experimental
64
120
  **/
65
121
  const DateInput2 = ({
66
122
  renderLabel,
67
123
  screenReaderLabels,
68
124
  isRequired = false,
69
125
  interaction = 'enabled',
70
- size = 'medium',
71
126
  isInline = false,
72
127
  value,
73
128
  messages,
@@ -75,77 +130,23 @@ const DateInput2 = ({
75
130
  onChange,
76
131
  onBlur,
77
132
  withYearPicker,
78
- onRequestValidateDate,
79
133
  invalidDateErrorMessage,
80
134
  locale,
81
135
  timezone,
82
136
  placeholder,
83
- formatDate = defaultDateFormatter,
137
+ dateFormat,
138
+ onRequestValidateDate,
84
139
  // margin, TODO enable this prop
85
140
  ...rest
86
141
  }) => {
87
- const _useState = (0, _react.useState)(''),
88
- _useState2 = (0, _slicedToArray2.default)(_useState, 2),
89
- selectedDate = _useState2[0],
90
- setSelectedDate = _useState2[1];
91
- const _useState3 = (0, _react.useState)(messages || []),
92
- _useState4 = (0, _slicedToArray2.default)(_useState3, 2),
93
- inputMessages = _useState4[0],
94
- setInputMessages = _useState4[1];
95
- const _useState5 = (0, _react.useState)(false),
96
- _useState6 = (0, _slicedToArray2.default)(_useState5, 2),
97
- showPopover = _useState6[0],
98
- setShowPopover = _useState6[1];
99
142
  const localeContext = (0, _react.useContext)(_ApplyLocaleContext.ApplyLocaleContext);
100
- (0, _react.useEffect)(() => {
101
- // when `value` is changed, validation removes the error message if passes
102
- // but it's NOT adding error message if validation fails for better UX
103
- validateInput(true);
104
- }, [value]);
105
- (0, _react.useEffect)(() => {
106
- setInputMessages(messages || []);
107
- }, [messages]);
108
- (0, _react.useEffect)(() => {
109
- setSelectedDate(parseDate(value || ''));
110
- }, []);
111
- const handleInputChange = (e, newValue, parsedDate = '') => {
112
- // blur event formats the input which shouldn't trigger parsing
113
- if (e.type !== 'blur') {
114
- setSelectedDate(parseDate(newValue));
115
- }
116
- onChange === null || onChange === void 0 ? void 0 : onChange(e, newValue, parsedDate);
117
- };
118
- const handleDateSelected = (dateString, _momentDate, e) => {
119
- const formattedDate = formatDate(dateString, getLocale(), getTimezone());
120
- const parsedDate = parseDate(dateString);
121
- setSelectedDate(parsedDate);
122
- handleInputChange(e, formattedDate, parsedDate);
123
- setShowPopover(false);
124
- onRequestValidateDate === null || onRequestValidateDate === void 0 ? void 0 : onRequestValidateDate(dateString, true);
125
- };
126
-
127
- // onlyRemoveError is used to remove the error msg immediately when the user inputs a valid date (and don't wait for blur event)
128
- const validateInput = (onlyRemoveError = false) => {
129
- // don't validate empty input
130
- if (!value || parseDate(value) || selectedDate) {
131
- setInputMessages(messages || []);
132
- return true;
133
- }
134
- // only show error if there is no user provided validation callback
135
- if (!onlyRemoveError && typeof invalidDateErrorMessage === 'string' && !onRequestValidateDate) {
136
- setInputMessages([{
137
- type: 'error',
138
- text: invalidDateErrorMessage
139
- }]);
140
- }
141
- return false;
142
- };
143
143
  const getLocale = () => {
144
144
  if (locale) {
145
145
  return locale;
146
146
  } else if (localeContext.locale) {
147
147
  return localeContext.locale;
148
148
  }
149
+ // default to the system's locale
149
150
  return _Locale.Locale.browserLocale();
150
151
  };
151
152
  const getTimezone = () => {
@@ -157,15 +158,84 @@ const DateInput2 = ({
157
158
  // default to the system's timezone
158
159
  return Intl.DateTimeFormat().resolvedOptions().timeZone;
159
160
  };
161
+ const _useState = (0, _react.useState)(messages || []),
162
+ _useState2 = (0, _slicedToArray2.default)(_useState, 2),
163
+ inputMessages = _useState2[0],
164
+ setInputMessages = _useState2[1];
165
+ const _useState3 = (0, _react.useState)(false),
166
+ _useState4 = (0, _slicedToArray2.default)(_useState3, 2),
167
+ showPopover = _useState4[0],
168
+ setShowPopover = _useState4[1];
169
+ (0, _react.useEffect)(() => {
170
+ setInputMessages(messages || []);
171
+ }, [messages]);
172
+ (0, _react.useEffect)(() => {
173
+ const _parseDate = parseDate(value),
174
+ _parseDate2 = (0, _slicedToArray2.default)(_parseDate, 2),
175
+ utcIsoDate = _parseDate2[1];
176
+ // clear error messages if date becomes valid
177
+ if (utcIsoDate || !value) {
178
+ setInputMessages(messages || []);
179
+ }
180
+ }, [value]);
181
+ const parseDate = (dateString = '') => {
182
+ let date = null;
183
+ if (dateFormat) {
184
+ if (typeof dateFormat === 'string') {
185
+ // use dateFormat instead of the user locale
186
+ date = parseLocaleDate(dateString, dateFormat, getTimezone());
187
+ } else if (dateFormat.parser) {
188
+ date = dateFormat.parser(dateString);
189
+ }
190
+ } else {
191
+ // no dateFormat prop passed, use locale for formatting
192
+ date = parseLocaleDate(dateString, getLocale(), getTimezone());
193
+ }
194
+ return date ? [formatDate(date), date.toISOString()] : ['', ''];
195
+ };
196
+ const formatDate = date => {
197
+ // use formatter function if provided
198
+ if (typeof dateFormat !== 'string' && dateFormat !== null && dateFormat !== void 0 && dateFormat.formatter) {
199
+ return dateFormat.formatter(date);
200
+ }
201
+ // if dateFormat set to a locale, use that, otherwise default to the user's locale
202
+ return date.toLocaleDateString(typeof dateFormat === 'string' ? dateFormat : getLocale(), {
203
+ timeZone: getTimezone(),
204
+ calendar: 'gregory',
205
+ numberingSystem: 'latn'
206
+ });
207
+ };
208
+ const handleInputChange = (e, newValue) => {
209
+ const _parseDate3 = parseDate(newValue),
210
+ _parseDate4 = (0, _slicedToArray2.default)(_parseDate3, 2),
211
+ utcIsoDate = _parseDate4[1];
212
+ onChange === null || onChange === void 0 ? void 0 : onChange(e, newValue, utcIsoDate);
213
+ };
214
+ const handleDateSelected = (dateString, _momentDate, e) => {
215
+ setShowPopover(false);
216
+ const newValue = formatDate(new Date(dateString));
217
+ onChange === null || onChange === void 0 ? void 0 : onChange(e, newValue, dateString);
218
+ onRequestValidateDate === null || onRequestValidateDate === void 0 ? void 0 : onRequestValidateDate(e, newValue, dateString);
219
+ };
160
220
  const handleBlur = e => {
161
- const isInputValid = validateInput(false);
162
- if (isInputValid && selectedDate) {
163
- const formattedDate = formatDate(selectedDate, getLocale(), getTimezone());
164
- handleInputChange(e, formattedDate, selectedDate);
221
+ const _parseDate5 = parseDate(value),
222
+ _parseDate6 = (0, _slicedToArray2.default)(_parseDate5, 2),
223
+ localeDate = _parseDate6[0],
224
+ utcIsoDate = _parseDate6[1];
225
+ if (localeDate) {
226
+ if (localeDate !== value) {
227
+ onChange === null || onChange === void 0 ? void 0 : onChange(e, localeDate, utcIsoDate);
228
+ }
229
+ } else if (value && invalidDateErrorMessage) {
230
+ setInputMessages([{
231
+ type: 'error',
232
+ text: invalidDateErrorMessage
233
+ }]);
165
234
  }
166
- onRequestValidateDate === null || onRequestValidateDate === void 0 ? void 0 : onRequestValidateDate(value, isInputValid);
167
- onBlur === null || onBlur === void 0 ? void 0 : onBlur(e);
235
+ onRequestValidateDate === null || onRequestValidateDate === void 0 ? void 0 : onRequestValidateDate(e, value || '', utcIsoDate);
236
+ onBlur === null || onBlur === void 0 ? void 0 : onBlur(e, value || '', utcIsoDate);
168
237
  };
238
+ const selectedDate = parseDate(value)[1];
169
239
  return (0, _emotion.jsx)(_TextInput.TextInput, Object.assign({}, (0, _passthroughProps.passthroughProps)(rest), {
170
240
  // margin={'large'} TODO add this prop to TextInput
171
241
  renderLabel: renderLabel,
@@ -175,7 +245,6 @@ const DateInput2 = ({
175
245
  value: value,
176
246
  placeholder: placeholder,
177
247
  width: width,
178
- size: size,
179
248
  display: isInline ? 'inline-block' : 'block',
180
249
  messages: inputMessages,
181
250
  interaction: interaction,
@@ -185,7 +254,6 @@ const DateInput2 = ({
185
254
  withBorder: false,
186
255
  screenReaderLabel: screenReaderLabels.calendarIcon,
187
256
  shape: "circle",
188
- size: size,
189
257
  interaction: interaction
190
258
  }, _IconCalendarMonthLin || (_IconCalendarMonthLin = (0, _emotion.jsx)(_IconCalendarMonthLine.IconCalendarMonthLine, null))),
191
259
  isShowingContent: showPopover,
@@ -36,7 +36,6 @@ const propTypes = exports.propTypes = {
36
36
  renderLabel: _propTypes.default.oneOfType([_propTypes.default.node, _propTypes.default.func]).isRequired,
37
37
  screenReaderLabels: _propTypes.default.object.isRequired,
38
38
  value: (0, _controllable.controllable)(_propTypes.default.string),
39
- size: _propTypes.default.oneOf(['small', 'medium', 'large']),
40
39
  placeholder: _propTypes.default.string,
41
40
  onChange: _propTypes.default.func,
42
41
  onBlur: _propTypes.default.func,
@@ -45,12 +44,10 @@ const propTypes = exports.propTypes = {
45
44
  isInline: _propTypes.default.bool,
46
45
  width: _propTypes.default.string,
47
46
  messages: _propTypes.default.arrayOf(_FormPropTypes.FormPropTypes.message),
48
- onRequestShowCalendar: _propTypes.default.func,
49
- onRequestHideCalendar: _propTypes.default.func,
50
- onRequestValidateDate: _propTypes.default.func,
51
47
  invalidDateErrorMessage: _propTypes.default.oneOfType([_propTypes.default.func, _propTypes.default.string]),
52
48
  locale: _propTypes.default.string,
53
49
  timezone: _propTypes.default.string,
54
50
  withYearPicker: _propTypes.default.object,
55
- formatDate: _propTypes.default.func
51
+ dateFormat: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.object]),
52
+ onRequestValidateDate: _propTypes.default.func
56
53
  };