@instructure/ui-date-time-input 8.36.1-snapshot-3 → 8.36.1-snapshot-7
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 +5 -2
- package/es/DateTimeInput/index.js +49 -58
- package/lib/DateTimeInput/index.js +49 -58
- package/package.json +18 -18
- package/src/DateTimeInput/README.md +6 -1
- package/src/DateTimeInput/index.tsx +32 -47
- package/src/DateTimeInput/props.ts +4 -3
- package/tsconfig.build.tsbuildinfo +1 -1
- package/types/DateTimeInput/index.d.ts +2 -1
- package/types/DateTimeInput/index.d.ts.map +1 -1
- package/types/DateTimeInput/props.d.ts +2 -1
- package/types/DateTimeInput/props.d.ts.map +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,9 +3,12 @@
|
|
|
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
|
-
## [8.36.1-snapshot-
|
|
6
|
+
## [8.36.1-snapshot-7](https://github.com/instructure/instructure-ui/compare/v8.36.0...v8.36.1-snapshot-7) (2023-04-12)
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* **ui-date-time-input:** dateTimeInput does not trigger invalidDateTimeMessage on blur ([307a3f4](https://github.com/instructure/instructure-ui/commit/307a3f4e288aefcc8ae01ef4c39e30015d2c021f))
|
|
9
12
|
|
|
10
13
|
|
|
11
14
|
|
|
@@ -75,16 +75,13 @@ let DateTimeInput = (_dec = testable(), _dec(_class = (_class2 = class DateTimeI
|
|
|
75
75
|
// timeout is needed here because handleDayClick could be called in the same
|
|
76
76
|
// frame, and it updates calendarSelectedDate which is read in here.
|
|
77
77
|
window.setTimeout(() => {
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
if (event.key === 'Enter') {
|
|
79
|
+
// user pressed enter, use the selected value in the calendar
|
|
80
|
+
this.updateStateBasedOnDateInput(this.state.calendarSelectedDate, event);
|
|
81
|
+
} else {
|
|
82
|
+
// user clicked outside/tabbed away/pressed esc, try to use the value in dateInputText
|
|
80
83
|
const dateParsed = this.tryParseDate(this.state.dateInputText);
|
|
81
84
|
this.updateStateBasedOnDateInput(dateParsed, event);
|
|
82
|
-
} else {
|
|
83
|
-
// user clicked outside or tabbed away or pressed esc, reset text
|
|
84
|
-
this.setState({
|
|
85
|
-
dateInputText: this.state.iso ? this.state.iso.format(this.dateFormat) : '',
|
|
86
|
-
calendarSelectedDate: this.state.iso ? this.state.iso.clone() : void 0
|
|
87
|
-
});
|
|
88
85
|
}
|
|
89
86
|
this.setState({
|
|
90
87
|
isShowingCalendar: false,
|
|
@@ -93,13 +90,10 @@ let DateTimeInput = (_dec = testable(), _dec(_class = (_class2 = class DateTimeI
|
|
|
93
90
|
}, 0);
|
|
94
91
|
};
|
|
95
92
|
this.handleTimeChange = (event, option) => {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
// if no date is set just return the input text, it will error
|
|
101
|
-
newValue = option.inputText;
|
|
102
|
-
}
|
|
93
|
+
// this.state.iso is undefined if date is invalid or not set.
|
|
94
|
+
// in this case recalculate with the dateInput's text which will result in
|
|
95
|
+
// an empty valid date (if isRequired is false) or an invalid date.
|
|
96
|
+
const newValue = this.state.iso ? option.value : this.state.dateInputText;
|
|
103
97
|
const newState = this.recalculateState(newValue, true, false);
|
|
104
98
|
this.changeStateIfNeeded(newState, event);
|
|
105
99
|
this.setState({
|
|
@@ -107,19 +101,26 @@ let DateTimeInput = (_dec = testable(), _dec(_class = (_class2 = class DateTimeI
|
|
|
107
101
|
});
|
|
108
102
|
};
|
|
109
103
|
this.changeStateIfNeeded = (newState, e) => {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
104
|
+
const dateStr = newState.dateInputText;
|
|
105
|
+
if (this.props.isRequired && !newState.iso || dateStr && dateStr.length > 0 && !newState.iso) {
|
|
106
|
+
const text = typeof this.props.invalidDateTimeMessage === 'function' ? this.props.invalidDateTimeMessage(dateStr ? dateStr : '') : this.props.invalidDateTimeMessage;
|
|
107
|
+
// eslint-disable-next-line no-param-reassign
|
|
108
|
+
newState.message = {
|
|
109
|
+
text: text,
|
|
110
|
+
type: 'error'
|
|
111
|
+
};
|
|
115
112
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
113
|
+
this.setState(newState);
|
|
114
|
+
if (this.areDifferentDates(this.state.iso, newState.iso)) {
|
|
115
|
+
var _this$props$onChange, _this$props, _newState$iso;
|
|
116
|
+
(_this$props$onChange = (_this$props = this.props).onChange) === null || _this$props$onChange === void 0 ? void 0 : _this$props$onChange.call(_this$props, e, (_newState$iso = newState.iso) === null || _newState$iso === void 0 ? void 0 : _newState$iso.toISOString());
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
this.areDifferentDates = (d1, d2) => {
|
|
120
|
+
if (!d1 && !d2) {
|
|
121
|
+
return false;
|
|
122
122
|
}
|
|
123
|
+
return !d1 || !d2 || !d1.isSame(d2);
|
|
123
124
|
};
|
|
124
125
|
this.handleBlur = e => {
|
|
125
126
|
// when TABbing from the DateInput to TimeInput or visa-versa, the blur
|
|
@@ -127,8 +128,8 @@ let DateTimeInput = (_dec = testable(), _dec(_class = (_class2 = class DateTimeI
|
|
|
127
128
|
// The timeout gives it a moment for that to happen
|
|
128
129
|
if (typeof this.props.onBlur === 'function') {
|
|
129
130
|
window.setTimeout(() => {
|
|
130
|
-
var _this$props$onBlur, _this$
|
|
131
|
-
(_this$props$onBlur = (_this$
|
|
131
|
+
var _this$props$onBlur, _this$props2;
|
|
132
|
+
(_this$props$onBlur = (_this$props2 = this.props).onBlur) === null || _this$props$onBlur === void 0 ? void 0 : _this$props$onBlur.call(_this$props2, e);
|
|
132
133
|
}, 0);
|
|
133
134
|
}
|
|
134
135
|
};
|
|
@@ -151,8 +152,7 @@ let DateTimeInput = (_dec = testable(), _dec(_class = (_class2 = class DateTimeI
|
|
|
151
152
|
});
|
|
152
153
|
this.setState({
|
|
153
154
|
calendarSelectedDate: toAlter,
|
|
154
|
-
renderedDate: toAlter.clone()
|
|
155
|
-
dateInputText: toAlter.format(this.dateFormat)
|
|
155
|
+
renderedDate: toAlter.clone()
|
|
156
156
|
});
|
|
157
157
|
};
|
|
158
158
|
this.handleSelectPrevDay = _event => {
|
|
@@ -169,8 +169,7 @@ let DateTimeInput = (_dec = testable(), _dec(_class = (_class2 = class DateTimeI
|
|
|
169
169
|
});
|
|
170
170
|
this.setState({
|
|
171
171
|
calendarSelectedDate: toAlter,
|
|
172
|
-
renderedDate: toAlter.clone()
|
|
173
|
-
dateInputText: toAlter.format(this.dateFormat)
|
|
172
|
+
renderedDate: toAlter.clone()
|
|
174
173
|
});
|
|
175
174
|
};
|
|
176
175
|
this.handleRenderNextMonth = _event => {
|
|
@@ -254,19 +253,11 @@ let DateTimeInput = (_dec = testable(), _dec(_class = (_class2 = class DateTimeI
|
|
|
254
253
|
renderedDate: parsed.clone()
|
|
255
254
|
};
|
|
256
255
|
}
|
|
257
|
-
if (dateStr.length > 0 || this.props.isRequired) {
|
|
258
|
-
const text = typeof this.props.invalidDateTimeMessage === 'function' ? this.props.invalidDateTimeMessage(dateStr) : this.props.invalidDateTimeMessage;
|
|
259
|
-
errorMsg = text ? {
|
|
260
|
-
text,
|
|
261
|
-
type: 'error'
|
|
262
|
-
} : void 0;
|
|
263
|
-
}
|
|
264
256
|
}
|
|
265
257
|
return {
|
|
266
258
|
iso: void 0,
|
|
267
259
|
calendarSelectedDate: void 0,
|
|
268
260
|
dateInputText: dateStr ? dateStr : '',
|
|
269
|
-
message: errorMsg,
|
|
270
261
|
renderedDate: DateTime.now(this.locale(), this.timezone()),
|
|
271
262
|
dateInputTextChanged: false
|
|
272
263
|
};
|
|
@@ -414,24 +405,24 @@ let DateTimeInput = (_dec = testable(), _dec(_class = (_class2 = class DateTimeI
|
|
|
414
405
|
});
|
|
415
406
|
}
|
|
416
407
|
render() {
|
|
417
|
-
const _this$
|
|
418
|
-
description = _this$
|
|
419
|
-
datePlaceholder = _this$
|
|
420
|
-
dateRenderLabel = _this$
|
|
421
|
-
dateInputRef = _this$
|
|
422
|
-
timeRenderLabel = _this$
|
|
423
|
-
timeFormat = _this$
|
|
424
|
-
timeStep = _this$
|
|
425
|
-
timeInputRef = _this$
|
|
426
|
-
locale = _this$
|
|
427
|
-
timezone = _this$
|
|
428
|
-
messages = _this$
|
|
429
|
-
layout = _this$
|
|
430
|
-
rowSpacing = _this$
|
|
431
|
-
colSpacing = _this$
|
|
432
|
-
isRequired = _this$
|
|
433
|
-
interaction = _this$
|
|
434
|
-
renderWeekdayLabels = _this$
|
|
408
|
+
const _this$props3 = this.props,
|
|
409
|
+
description = _this$props3.description,
|
|
410
|
+
datePlaceholder = _this$props3.datePlaceholder,
|
|
411
|
+
dateRenderLabel = _this$props3.dateRenderLabel,
|
|
412
|
+
dateInputRef = _this$props3.dateInputRef,
|
|
413
|
+
timeRenderLabel = _this$props3.timeRenderLabel,
|
|
414
|
+
timeFormat = _this$props3.timeFormat,
|
|
415
|
+
timeStep = _this$props3.timeStep,
|
|
416
|
+
timeInputRef = _this$props3.timeInputRef,
|
|
417
|
+
locale = _this$props3.locale,
|
|
418
|
+
timezone = _this$props3.timezone,
|
|
419
|
+
messages = _this$props3.messages,
|
|
420
|
+
layout = _this$props3.layout,
|
|
421
|
+
rowSpacing = _this$props3.rowSpacing,
|
|
422
|
+
colSpacing = _this$props3.colSpacing,
|
|
423
|
+
isRequired = _this$props3.isRequired,
|
|
424
|
+
interaction = _this$props3.interaction,
|
|
425
|
+
renderWeekdayLabels = _this$props3.renderWeekdayLabels;
|
|
435
426
|
return /*#__PURE__*/React.createElement(FormFieldGroup, {
|
|
436
427
|
description: description,
|
|
437
428
|
layout: layout,
|
|
@@ -60,16 +60,13 @@ let DateTimeInput = (_dec = (0, _testable.testable)(), _dec(_class = (_class2 =
|
|
|
60
60
|
// timeout is needed here because handleDayClick could be called in the same
|
|
61
61
|
// frame, and it updates calendarSelectedDate which is read in here.
|
|
62
62
|
window.setTimeout(() => {
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
if (event.key === 'Enter') {
|
|
64
|
+
// user pressed enter, use the selected value in the calendar
|
|
65
|
+
this.updateStateBasedOnDateInput(this.state.calendarSelectedDate, event);
|
|
66
|
+
} else {
|
|
67
|
+
// user clicked outside/tabbed away/pressed esc, try to use the value in dateInputText
|
|
65
68
|
const dateParsed = this.tryParseDate(this.state.dateInputText);
|
|
66
69
|
this.updateStateBasedOnDateInput(dateParsed, event);
|
|
67
|
-
} else {
|
|
68
|
-
// user clicked outside or tabbed away or pressed esc, reset text
|
|
69
|
-
this.setState({
|
|
70
|
-
dateInputText: this.state.iso ? this.state.iso.format(this.dateFormat) : '',
|
|
71
|
-
calendarSelectedDate: this.state.iso ? this.state.iso.clone() : void 0
|
|
72
|
-
});
|
|
73
70
|
}
|
|
74
71
|
this.setState({
|
|
75
72
|
isShowingCalendar: false,
|
|
@@ -78,13 +75,10 @@ let DateTimeInput = (_dec = (0, _testable.testable)(), _dec(_class = (_class2 =
|
|
|
78
75
|
}, 0);
|
|
79
76
|
};
|
|
80
77
|
this.handleTimeChange = (event, option) => {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
// if no date is set just return the input text, it will error
|
|
86
|
-
newValue = option.inputText;
|
|
87
|
-
}
|
|
78
|
+
// this.state.iso is undefined if date is invalid or not set.
|
|
79
|
+
// in this case recalculate with the dateInput's text which will result in
|
|
80
|
+
// an empty valid date (if isRequired is false) or an invalid date.
|
|
81
|
+
const newValue = this.state.iso ? option.value : this.state.dateInputText;
|
|
88
82
|
const newState = this.recalculateState(newValue, true, false);
|
|
89
83
|
this.changeStateIfNeeded(newState, event);
|
|
90
84
|
this.setState({
|
|
@@ -92,19 +86,26 @@ let DateTimeInput = (_dec = (0, _testable.testable)(), _dec(_class = (_class2 =
|
|
|
92
86
|
});
|
|
93
87
|
};
|
|
94
88
|
this.changeStateIfNeeded = (newState, e) => {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
89
|
+
const dateStr = newState.dateInputText;
|
|
90
|
+
if (this.props.isRequired && !newState.iso || dateStr && dateStr.length > 0 && !newState.iso) {
|
|
91
|
+
const text = typeof this.props.invalidDateTimeMessage === 'function' ? this.props.invalidDateTimeMessage(dateStr ? dateStr : '') : this.props.invalidDateTimeMessage;
|
|
92
|
+
// eslint-disable-next-line no-param-reassign
|
|
93
|
+
newState.message = {
|
|
94
|
+
text: text,
|
|
95
|
+
type: 'error'
|
|
96
|
+
};
|
|
100
97
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
98
|
+
this.setState(newState);
|
|
99
|
+
if (this.areDifferentDates(this.state.iso, newState.iso)) {
|
|
100
|
+
var _this$props$onChange, _this$props, _newState$iso;
|
|
101
|
+
(_this$props$onChange = (_this$props = this.props).onChange) === null || _this$props$onChange === void 0 ? void 0 : _this$props$onChange.call(_this$props, e, (_newState$iso = newState.iso) === null || _newState$iso === void 0 ? void 0 : _newState$iso.toISOString());
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
this.areDifferentDates = (d1, d2) => {
|
|
105
|
+
if (!d1 && !d2) {
|
|
106
|
+
return false;
|
|
107
107
|
}
|
|
108
|
+
return !d1 || !d2 || !d1.isSame(d2);
|
|
108
109
|
};
|
|
109
110
|
this.handleBlur = e => {
|
|
110
111
|
// when TABbing from the DateInput to TimeInput or visa-versa, the blur
|
|
@@ -112,8 +113,8 @@ let DateTimeInput = (_dec = (0, _testable.testable)(), _dec(_class = (_class2 =
|
|
|
112
113
|
// The timeout gives it a moment for that to happen
|
|
113
114
|
if (typeof this.props.onBlur === 'function') {
|
|
114
115
|
window.setTimeout(() => {
|
|
115
|
-
var _this$props$onBlur, _this$
|
|
116
|
-
(_this$props$onBlur = (_this$
|
|
116
|
+
var _this$props$onBlur, _this$props2;
|
|
117
|
+
(_this$props$onBlur = (_this$props2 = this.props).onBlur) === null || _this$props$onBlur === void 0 ? void 0 : _this$props$onBlur.call(_this$props2, e);
|
|
117
118
|
}, 0);
|
|
118
119
|
}
|
|
119
120
|
};
|
|
@@ -136,8 +137,7 @@ let DateTimeInput = (_dec = (0, _testable.testable)(), _dec(_class = (_class2 =
|
|
|
136
137
|
});
|
|
137
138
|
this.setState({
|
|
138
139
|
calendarSelectedDate: toAlter,
|
|
139
|
-
renderedDate: toAlter.clone()
|
|
140
|
-
dateInputText: toAlter.format(this.dateFormat)
|
|
140
|
+
renderedDate: toAlter.clone()
|
|
141
141
|
});
|
|
142
142
|
};
|
|
143
143
|
this.handleSelectPrevDay = _event => {
|
|
@@ -154,8 +154,7 @@ let DateTimeInput = (_dec = (0, _testable.testable)(), _dec(_class = (_class2 =
|
|
|
154
154
|
});
|
|
155
155
|
this.setState({
|
|
156
156
|
calendarSelectedDate: toAlter,
|
|
157
|
-
renderedDate: toAlter.clone()
|
|
158
|
-
dateInputText: toAlter.format(this.dateFormat)
|
|
157
|
+
renderedDate: toAlter.clone()
|
|
159
158
|
});
|
|
160
159
|
};
|
|
161
160
|
this.handleRenderNextMonth = _event => {
|
|
@@ -239,19 +238,11 @@ let DateTimeInput = (_dec = (0, _testable.testable)(), _dec(_class = (_class2 =
|
|
|
239
238
|
renderedDate: parsed.clone()
|
|
240
239
|
};
|
|
241
240
|
}
|
|
242
|
-
if (dateStr.length > 0 || this.props.isRequired) {
|
|
243
|
-
const text = typeof this.props.invalidDateTimeMessage === 'function' ? this.props.invalidDateTimeMessage(dateStr) : this.props.invalidDateTimeMessage;
|
|
244
|
-
errorMsg = text ? {
|
|
245
|
-
text,
|
|
246
|
-
type: 'error'
|
|
247
|
-
} : void 0;
|
|
248
|
-
}
|
|
249
241
|
}
|
|
250
242
|
return {
|
|
251
243
|
iso: void 0,
|
|
252
244
|
calendarSelectedDate: void 0,
|
|
253
245
|
dateInputText: dateStr ? dateStr : '',
|
|
254
|
-
message: errorMsg,
|
|
255
246
|
renderedDate: _DateTime.DateTime.now(this.locale(), this.timezone()),
|
|
256
247
|
dateInputTextChanged: false
|
|
257
248
|
};
|
|
@@ -399,24 +390,24 @@ let DateTimeInput = (_dec = (0, _testable.testable)(), _dec(_class = (_class2 =
|
|
|
399
390
|
});
|
|
400
391
|
}
|
|
401
392
|
render() {
|
|
402
|
-
const _this$
|
|
403
|
-
description = _this$
|
|
404
|
-
datePlaceholder = _this$
|
|
405
|
-
dateRenderLabel = _this$
|
|
406
|
-
dateInputRef = _this$
|
|
407
|
-
timeRenderLabel = _this$
|
|
408
|
-
timeFormat = _this$
|
|
409
|
-
timeStep = _this$
|
|
410
|
-
timeInputRef = _this$
|
|
411
|
-
locale = _this$
|
|
412
|
-
timezone = _this$
|
|
413
|
-
messages = _this$
|
|
414
|
-
layout = _this$
|
|
415
|
-
rowSpacing = _this$
|
|
416
|
-
colSpacing = _this$
|
|
417
|
-
isRequired = _this$
|
|
418
|
-
interaction = _this$
|
|
419
|
-
renderWeekdayLabels = _this$
|
|
393
|
+
const _this$props3 = this.props,
|
|
394
|
+
description = _this$props3.description,
|
|
395
|
+
datePlaceholder = _this$props3.datePlaceholder,
|
|
396
|
+
dateRenderLabel = _this$props3.dateRenderLabel,
|
|
397
|
+
dateInputRef = _this$props3.dateInputRef,
|
|
398
|
+
timeRenderLabel = _this$props3.timeRenderLabel,
|
|
399
|
+
timeFormat = _this$props3.timeFormat,
|
|
400
|
+
timeStep = _this$props3.timeStep,
|
|
401
|
+
timeInputRef = _this$props3.timeInputRef,
|
|
402
|
+
locale = _this$props3.locale,
|
|
403
|
+
timezone = _this$props3.timezone,
|
|
404
|
+
messages = _this$props3.messages,
|
|
405
|
+
layout = _this$props3.layout,
|
|
406
|
+
rowSpacing = _this$props3.rowSpacing,
|
|
407
|
+
colSpacing = _this$props3.colSpacing,
|
|
408
|
+
isRequired = _this$props3.isRequired,
|
|
409
|
+
interaction = _this$props3.interaction,
|
|
410
|
+
renderWeekdayLabels = _this$props3.renderWeekdayLabels;
|
|
420
411
|
return /*#__PURE__*/_react.default.createElement(_FormFieldGroup.FormFieldGroup, {
|
|
421
412
|
description: description,
|
|
422
413
|
layout: layout,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@instructure/ui-date-time-input",
|
|
3
|
-
"version": "8.36.1-snapshot-
|
|
3
|
+
"version": "8.36.1-snapshot-7",
|
|
4
4
|
"description": "A UI component that allows to select date and time.",
|
|
5
5
|
"author": "Instructure, Inc. Engineering and Product Design",
|
|
6
6
|
"module": "./es/index.js",
|
|
@@ -23,26 +23,26 @@
|
|
|
23
23
|
},
|
|
24
24
|
"license": "MIT",
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@instructure/ui-babel-preset": "8.36.1-snapshot-
|
|
27
|
-
"@instructure/ui-test-locator": "8.36.1-snapshot-
|
|
28
|
-
"@instructure/ui-test-utils": "8.36.1-snapshot-
|
|
26
|
+
"@instructure/ui-babel-preset": "8.36.1-snapshot-7",
|
|
27
|
+
"@instructure/ui-test-locator": "8.36.1-snapshot-7",
|
|
28
|
+
"@instructure/ui-test-utils": "8.36.1-snapshot-7"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@babel/runtime": "^7.20.13",
|
|
32
|
-
"@instructure/debounce": "8.36.1-snapshot-
|
|
33
|
-
"@instructure/emotion": "8.36.1-snapshot-
|
|
34
|
-
"@instructure/ui-a11y-content": "8.36.1-snapshot-
|
|
35
|
-
"@instructure/ui-buttons": "8.36.1-snapshot-
|
|
36
|
-
"@instructure/ui-calendar": "8.36.1-snapshot-
|
|
37
|
-
"@instructure/ui-date-input": "8.36.1-snapshot-
|
|
38
|
-
"@instructure/ui-form-field": "8.36.1-snapshot-
|
|
39
|
-
"@instructure/ui-i18n": "8.36.1-snapshot-
|
|
40
|
-
"@instructure/ui-icons": "8.36.1-snapshot-
|
|
41
|
-
"@instructure/ui-prop-types": "8.36.1-snapshot-
|
|
42
|
-
"@instructure/ui-react-utils": "8.36.1-snapshot-
|
|
43
|
-
"@instructure/ui-testable": "8.36.1-snapshot-
|
|
44
|
-
"@instructure/ui-time-select": "8.36.1-snapshot-
|
|
45
|
-
"@instructure/ui-utils": "8.36.1-snapshot-
|
|
32
|
+
"@instructure/debounce": "8.36.1-snapshot-7",
|
|
33
|
+
"@instructure/emotion": "8.36.1-snapshot-7",
|
|
34
|
+
"@instructure/ui-a11y-content": "8.36.1-snapshot-7",
|
|
35
|
+
"@instructure/ui-buttons": "8.36.1-snapshot-7",
|
|
36
|
+
"@instructure/ui-calendar": "8.36.1-snapshot-7",
|
|
37
|
+
"@instructure/ui-date-input": "8.36.1-snapshot-7",
|
|
38
|
+
"@instructure/ui-form-field": "8.36.1-snapshot-7",
|
|
39
|
+
"@instructure/ui-i18n": "8.36.1-snapshot-7",
|
|
40
|
+
"@instructure/ui-icons": "8.36.1-snapshot-7",
|
|
41
|
+
"@instructure/ui-prop-types": "8.36.1-snapshot-7",
|
|
42
|
+
"@instructure/ui-react-utils": "8.36.1-snapshot-7",
|
|
43
|
+
"@instructure/ui-testable": "8.36.1-snapshot-7",
|
|
44
|
+
"@instructure/ui-time-select": "8.36.1-snapshot-7",
|
|
45
|
+
"@instructure/ui-utils": "8.36.1-snapshot-7",
|
|
46
46
|
"prop-types": "^15.8.1"
|
|
47
47
|
},
|
|
48
48
|
"peerDependencies": {
|
|
@@ -63,9 +63,14 @@ class Example extends React.Component {
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
onChange = (e, isoDate) => {
|
|
66
|
+
let messages = []
|
|
67
|
+
if (!isoDate) {
|
|
68
|
+
// this happens if an invalid date is entered
|
|
69
|
+
this.setState({ messages })
|
|
70
|
+
return
|
|
71
|
+
}
|
|
66
72
|
const now = new Date()
|
|
67
73
|
const newValue = new Date(isoDate)
|
|
68
|
-
let messages = []
|
|
69
74
|
if ( newValue.valueOf() <= now.valueOf()) {
|
|
70
75
|
messages = [{text: 'That date-time is in the past', type: 'hint'}]
|
|
71
76
|
}
|
|
@@ -169,19 +169,11 @@ class DateTimeInput extends Component<DateTimeInputProps, DateTimeInputState> {
|
|
|
169
169
|
renderedDate: parsed.clone()
|
|
170
170
|
}
|
|
171
171
|
}
|
|
172
|
-
if (dateStr.length > 0 || this.props.isRequired) {
|
|
173
|
-
const text =
|
|
174
|
-
typeof this.props.invalidDateTimeMessage === 'function'
|
|
175
|
-
? this.props.invalidDateTimeMessage(dateStr)
|
|
176
|
-
: this.props.invalidDateTimeMessage
|
|
177
|
-
errorMsg = text ? { text, type: 'error' } : undefined
|
|
178
|
-
}
|
|
179
172
|
}
|
|
180
173
|
return {
|
|
181
174
|
iso: undefined,
|
|
182
175
|
calendarSelectedDate: undefined,
|
|
183
176
|
dateInputText: dateStr ? dateStr : '',
|
|
184
|
-
message: errorMsg,
|
|
185
177
|
renderedDate: DateTime.now(this.locale(), this.timezone()),
|
|
186
178
|
dateInputTextChanged: false
|
|
187
179
|
}
|
|
@@ -256,30 +248,20 @@ class DateTimeInput extends Component<DateTimeInputProps, DateTimeInputState> {
|
|
|
256
248
|
// timeout is needed here because handleDayClick could be called in the same
|
|
257
249
|
// frame, and it updates calendarSelectedDate which is read in here.
|
|
258
250
|
window.setTimeout(() => {
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
this.state.
|
|
262
|
-
|
|
263
|
-
|
|
251
|
+
if ((event as React.KeyboardEvent).key === 'Enter') {
|
|
252
|
+
// user pressed enter, use the selected value in the calendar
|
|
253
|
+
this.updateStateBasedOnDateInput(this.state.calendarSelectedDate, event)
|
|
254
|
+
} else {
|
|
255
|
+
// user clicked outside/tabbed away/pressed esc, try to use the value in dateInputText
|
|
264
256
|
const dateParsed = this.tryParseDate(this.state.dateInputText)
|
|
265
257
|
this.updateStateBasedOnDateInput(dateParsed, event)
|
|
266
|
-
} else {
|
|
267
|
-
// user clicked outside or tabbed away or pressed esc, reset text
|
|
268
|
-
this.setState({
|
|
269
|
-
dateInputText: this.state.iso
|
|
270
|
-
? this.state.iso.format(this.dateFormat)
|
|
271
|
-
: '',
|
|
272
|
-
calendarSelectedDate: this.state.iso
|
|
273
|
-
? this.state.iso.clone()
|
|
274
|
-
: undefined
|
|
275
|
-
})
|
|
276
258
|
}
|
|
277
259
|
this.setState({ isShowingCalendar: false, dateInputTextChanged: false })
|
|
278
260
|
}, 0)
|
|
279
261
|
}
|
|
280
262
|
|
|
281
263
|
updateStateBasedOnDateInput(
|
|
282
|
-
dateParsed: Moment | null,
|
|
264
|
+
dateParsed: Moment | null | undefined,
|
|
283
265
|
event: SyntheticEvent
|
|
284
266
|
) {
|
|
285
267
|
let newState
|
|
@@ -316,34 +298,39 @@ class DateTimeInput extends Component<DateTimeInputProps, DateTimeInputState> {
|
|
|
316
298
|
event: SyntheticEvent,
|
|
317
299
|
option: { value?: string; inputText: string }
|
|
318
300
|
) => {
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
// if no date is set just return the input text, it will error
|
|
324
|
-
newValue = option.inputText
|
|
325
|
-
}
|
|
301
|
+
// this.state.iso is undefined if date is invalid or not set.
|
|
302
|
+
// in this case recalculate with the dateInput's text which will result in
|
|
303
|
+
// an empty valid date (if isRequired is false) or an invalid date.
|
|
304
|
+
const newValue = this.state.iso ? option.value : this.state.dateInputText
|
|
326
305
|
const newState = this.recalculateState(newValue, true, false)
|
|
327
|
-
|
|
328
306
|
this.changeStateIfNeeded(newState, event)
|
|
329
307
|
this.setState({ timeSelectValue: option.value })
|
|
330
308
|
}
|
|
331
309
|
|
|
332
310
|
changeStateIfNeeded = (newState: DateTimeInputState, e: SyntheticEvent) => {
|
|
333
|
-
|
|
334
|
-
if (!newState.iso && !this.state.iso) {
|
|
335
|
-
return
|
|
336
|
-
}
|
|
311
|
+
const dateStr = newState.dateInputText
|
|
337
312
|
if (
|
|
338
|
-
|
|
339
|
-
!newState.iso
|
|
340
|
-
!this.state.iso.isSame(newState.iso)
|
|
313
|
+
(this.props.isRequired && !newState.iso) ||
|
|
314
|
+
(dateStr && dateStr.length > 0 && !newState.iso)
|
|
341
315
|
) {
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
316
|
+
const text =
|
|
317
|
+
typeof this.props.invalidDateTimeMessage === 'function'
|
|
318
|
+
? this.props.invalidDateTimeMessage(dateStr ? dateStr : '')
|
|
319
|
+
: this.props.invalidDateTimeMessage
|
|
320
|
+
// eslint-disable-next-line no-param-reassign
|
|
321
|
+
newState.message = { text: text, type: 'error' }
|
|
322
|
+
}
|
|
323
|
+
this.setState(newState)
|
|
324
|
+
if (this.areDifferentDates(this.state.iso, newState.iso)) {
|
|
325
|
+
this.props.onChange?.(e, newState.iso?.toISOString())
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
areDifferentDates = (d1?: Moment, d2?: Moment) => {
|
|
330
|
+
if (!d1 && !d2) {
|
|
331
|
+
return false
|
|
346
332
|
}
|
|
333
|
+
return !d1 || !d2 || !d1.isSame(d2)
|
|
347
334
|
}
|
|
348
335
|
|
|
349
336
|
handleBlur = (e: SyntheticEvent) => {
|
|
@@ -373,8 +360,7 @@ class DateTimeInput extends Component<DateTimeInputProps, DateTimeInputState> {
|
|
|
373
360
|
toAlter.add({ days: 1 })
|
|
374
361
|
this.setState({
|
|
375
362
|
calendarSelectedDate: toAlter,
|
|
376
|
-
renderedDate: toAlter.clone()
|
|
377
|
-
dateInputText: toAlter.format(this.dateFormat)
|
|
363
|
+
renderedDate: toAlter.clone()
|
|
378
364
|
})
|
|
379
365
|
}
|
|
380
366
|
|
|
@@ -390,8 +376,7 @@ class DateTimeInput extends Component<DateTimeInputProps, DateTimeInputState> {
|
|
|
390
376
|
toAlter.subtract({ days: 1 })
|
|
391
377
|
this.setState({
|
|
392
378
|
calendarSelectedDate: toAlter,
|
|
393
|
-
renderedDate: toAlter.clone()
|
|
394
|
-
dateInputText: toAlter.format(this.dateFormat)
|
|
379
|
+
renderedDate: toAlter.clone()
|
|
395
380
|
})
|
|
396
381
|
}
|
|
397
382
|
|
|
@@ -176,7 +176,8 @@ type DateTimeInputProps = {
|
|
|
176
176
|
)[]
|
|
177
177
|
/**
|
|
178
178
|
* Specifies if the input is required (its passed down to the native DOM
|
|
179
|
-
* elements).
|
|
179
|
+
* elements). If its `true` then an empty input will produce an error message
|
|
180
|
+
* (`invalidDateTimeMessage`)
|
|
180
181
|
*/
|
|
181
182
|
isRequired?: boolean
|
|
182
183
|
/**
|
|
@@ -232,8 +233,8 @@ type DateTimeInputState = {
|
|
|
232
233
|
// the date rendered by the opened calendar. Not selected just determines
|
|
233
234
|
// which month/year to show
|
|
234
235
|
renderedDate: Moment
|
|
235
|
-
// The value currently displayed in the
|
|
236
|
-
// Just the
|
|
236
|
+
// The value currently displayed in the dateInput component.
|
|
237
|
+
// Just the date part is visible
|
|
237
238
|
dateInputText: string
|
|
238
239
|
// The value currently displayed in the timeSelect component as ISO datetime
|
|
239
240
|
timeSelectValue?: string
|