@instructure/ui-date-time-input 8.52.1-snapshot-11 → 8.53.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,184 +3,98 @@
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.52.1-snapshot-11](https://github.com/instructure/instructure-ui/compare/v8.52.0...v8.52.1-snapshot-11) (2024-02-08)
7
-
6
+ # [8.53.0](https://github.com/instructure/instructure-ui/compare/v8.52.0...v8.53.0) (2024-02-08)
8
7
 
9
8
  ### Features
10
9
 
11
- * **many:** provide defaults to dateInput for easier setup and use ([dcefc4e](https://github.com/instructure/instructure-ui/commit/dcefc4e259118264d76dfd248b01682a7c2ef661))
12
- * **ui-date-time-input:** add placeholder to datetimeinput's timeselect ([3ec8cc3](https://github.com/instructure/instructure-ui/commit/3ec8cc31f06ee570b704f88b09739a0868da9ff7))
13
-
14
-
15
-
16
-
10
+ - **many:** provide defaults to dateInput for easier setup and use ([dcefc4e](https://github.com/instructure/instructure-ui/commit/dcefc4e259118264d76dfd248b01682a7c2ef661))
11
+ - **ui-date-time-input:** add initialTimeForNewDate prop to datetimeinput ([33711a3](https://github.com/instructure/instructure-ui/commit/33711a3d899c34913aafd40c7dec90faabc88cd0))
12
+ - **ui-date-time-input:** add placeholder to datetimeinput's timeselect ([3ec8cc3](https://github.com/instructure/instructure-ui/commit/3ec8cc31f06ee570b704f88b09739a0868da9ff7))
17
13
 
18
14
  # [8.52.0](https://github.com/instructure/instructure-ui/compare/v8.51.0...v8.52.0) (2024-02-02)
19
15
 
20
16
  **Note:** Version bump only for package @instructure/ui-date-time-input
21
17
 
22
-
23
-
24
-
25
-
26
18
  # [8.51.0](https://github.com/instructure/instructure-ui/compare/v8.50.0...v8.51.0) (2023-12-14)
27
19
 
28
-
29
20
  ### Features
30
21
 
31
- * **ui-date-time-input:** add showMessages prop ([5212a19](https://github.com/instructure/instructure-ui/commit/5212a192b56fed621c80a697579fc164f9592391))
32
-
33
-
34
-
35
-
22
+ - **ui-date-time-input:** add showMessages prop ([5212a19](https://github.com/instructure/instructure-ui/commit/5212a192b56fed621c80a697579fc164f9592391))
36
23
 
37
24
  # [8.50.0](https://github.com/instructure/instructure-ui/compare/v8.49.0...v8.50.0) (2023-12-05)
38
25
 
39
26
  **Note:** Version bump only for package @instructure/ui-date-time-input
40
27
 
41
-
42
-
43
-
44
-
45
28
  # [8.49.0](https://github.com/instructure/instructure-ui/compare/v8.48.3...v8.49.0) (2023-11-24)
46
29
 
47
30
  **Note:** Version bump only for package @instructure/ui-date-time-input
48
31
 
49
-
50
-
51
-
52
-
53
32
  ## [8.48.3](https://github.com/instructure/instructure-ui/compare/v8.48.2...v8.48.3) (2023-11-23)
54
33
 
55
34
  **Note:** Version bump only for package @instructure/ui-date-time-input
56
35
 
57
-
58
-
59
-
60
-
61
36
  ## [8.48.2](https://github.com/instructure/instructure-ui/compare/v8.48.1...v8.48.2) (2023-11-21)
62
37
 
63
38
  **Note:** Version bump only for package @instructure/ui-date-time-input
64
39
 
65
-
66
-
67
-
68
-
69
40
  ## [8.48.1](https://github.com/instructure/instructure-ui/compare/v8.48.0...v8.48.1) (2023-11-17)
70
41
 
71
42
  **Note:** Version bump only for package @instructure/ui-date-time-input
72
43
 
73
-
74
-
75
-
76
-
77
44
  # [8.48.0](https://github.com/instructure/instructure-ui/compare/v8.47.1...v8.48.0) (2023-11-10)
78
45
 
79
46
  **Note:** Version bump only for package @instructure/ui-date-time-input
80
47
 
81
-
82
-
83
-
84
-
85
48
  ## [8.47.1](https://github.com/instructure/instructure-ui/compare/v8.47.0...v8.47.1) (2023-11-06)
86
49
 
87
50
  **Note:** Version bump only for package @instructure/ui-date-time-input
88
51
 
89
-
90
-
91
-
92
-
93
52
  # [8.47.0](https://github.com/instructure/instructure-ui/compare/v8.46.1...v8.47.0) (2023-10-27)
94
53
 
95
-
96
54
  ### Bug Fixes
97
55
 
98
- * **ui-date-time-input:** clear TimeSelect value when DateInput value is cleared ([b1a58e5](https://github.com/instructure/instructure-ui/commit/b1a58e5c04822da491966bc0a79403b30749ff7e))
99
-
100
-
101
-
102
-
56
+ - **ui-date-time-input:** clear TimeSelect value when DateInput value is cleared ([b1a58e5](https://github.com/instructure/instructure-ui/commit/b1a58e5c04822da491966bc0a79403b30749ff7e))
103
57
 
104
58
  ## [8.46.1](https://github.com/instructure/instructure-ui/compare/v8.46.0...v8.46.1) (2023-10-13)
105
59
 
106
60
  **Note:** Version bump only for package @instructure/ui-date-time-input
107
61
 
108
-
109
-
110
-
111
-
112
62
  # [8.46.0](https://github.com/instructure/instructure-ui/compare/v8.45.0...v8.46.0) (2023-10-11)
113
63
 
114
64
  **Note:** Version bump only for package @instructure/ui-date-time-input
115
65
 
116
-
117
-
118
-
119
-
120
66
  # [8.45.0](https://github.com/instructure/instructure-ui/compare/v8.44.0...v8.45.0) (2023-10-03)
121
67
 
122
68
  **Note:** Version bump only for package @instructure/ui-date-time-input
123
69
 
124
-
125
-
126
-
127
-
128
70
  # [8.44.0](https://github.com/instructure/instructure-ui/compare/v8.43.1...v8.44.0) (2023-09-21)
129
71
 
130
72
  **Note:** Version bump only for package @instructure/ui-date-time-input
131
73
 
132
-
133
-
134
-
135
-
136
74
  ## [8.43.1](https://github.com/instructure/instructure-ui/compare/v8.43.0...v8.43.1) (2023-09-11)
137
75
 
138
76
  **Note:** Version bump only for package @instructure/ui-date-time-input
139
77
 
140
-
141
-
142
-
143
-
144
78
  # [8.43.0](https://github.com/instructure/instructure-ui/compare/v8.41.1...v8.43.0) (2023-09-07)
145
79
 
146
80
  **Note:** Version bump only for package @instructure/ui-date-time-input
147
81
 
148
-
149
-
150
-
151
-
152
82
  # [8.42.0](https://github.com/instructure/instructure-ui/compare/v8.41.1...v8.42.0) (2023-09-07)
153
83
 
154
84
  **Note:** Version bump only for package @instructure/ui-date-time-input
155
85
 
156
-
157
-
158
-
159
-
160
86
  ## [8.41.1](https://github.com/instructure/instructure-ui/compare/v8.41.0...v8.41.1) (2023-08-24)
161
87
 
162
88
  **Note:** Version bump only for package @instructure/ui-date-time-input
163
89
 
164
-
165
-
166
-
167
-
168
90
  # [8.41.0](https://github.com/instructure/instructure-ui/compare/v8.40.1...v8.41.0) (2023-08-21)
169
91
 
170
92
  **Note:** Version bump only for package @instructure/ui-date-time-input
171
93
 
172
-
173
-
174
-
175
-
176
94
  ## [8.40.1](https://github.com/instructure/instructure-ui/compare/v8.40.0...v8.40.1) (2023-08-18)
177
95
 
178
96
  **Note:** Version bump only for package @instructure/ui-date-time-input
179
97
 
180
-
181
-
182
-
183
-
184
98
  # [8.40.0](https://github.com/instructure/instructure-ui/compare/v8.39.0...v8.40.0) (2023-08-17)
185
99
 
186
100
  **Note:** Version bump only for package @instructure/ui-date-time-input
@@ -0,0 +1,167 @@
1
+ /*
2
+ * The MIT License (MIT)
3
+ *
4
+ * Copyright (c) 2018 - present Instructure, Inc.
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ * of this software and associated documentation files (the "Software"), to deal
8
+ * in the Software without restriction, including without limitation the rights
9
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ * copies of the Software, and to permit persons to whom the Software is
11
+ * furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in all
14
+ * copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ * SOFTWARE.
23
+ */
24
+
25
+ import React from 'react';
26
+ import { fireEvent, render, screen } from '@testing-library/react';
27
+ import '@testing-library/jest-dom';
28
+ import { userEvent } from '@testing-library/user-event';
29
+ import DateTimeInput from '../index';
30
+ describe('<DateTimeInput />', () => {
31
+ it("should change value of TimeSelect to initialTimeForNewDate prop's value", async () => {
32
+ const locale = 'en-US';
33
+ const timezone = 'US/Eastern';
34
+ render( /*#__PURE__*/React.createElement(DateTimeInput, {
35
+ description: "date time",
36
+ prevMonthLabel: "Previous month",
37
+ nextMonthLabel: "Next month",
38
+ dateRenderLabel: "date",
39
+ timeRenderLabel: "time",
40
+ invalidDateTimeMessage: "whoops",
41
+ locale: locale,
42
+ timezone: timezone,
43
+ initialTimeForNewDate: "05:05"
44
+ }));
45
+ const input = screen.getAllByRole('combobox')[0];
46
+ fireEvent.click(input);
47
+ const firstDay = screen.getByText('15');
48
+ await userEvent.click(firstDay);
49
+ const allInputs = screen.getAllByRole('combobox');
50
+ const targetInput = allInputs.find(input => input.value === '5:05 AM');
51
+ expect(targetInput).toBeInTheDocument();
52
+ });
53
+ it("should throw warning if initialTimeForNewDate prop's value is not HH:MM", async () => {
54
+ const locale = 'en-US';
55
+ const timezone = 'US/Eastern';
56
+ const consoleError = jest.spyOn(console, 'error').mockImplementation(() => {});
57
+ const initialTimeForNewDate = 'WRONG_FORMAT';
58
+ render( /*#__PURE__*/React.createElement(DateTimeInput, {
59
+ description: "date time",
60
+ prevMonthLabel: "Previous month",
61
+ nextMonthLabel: "Next month",
62
+ dateRenderLabel: "date",
63
+ timeRenderLabel: "time",
64
+ invalidDateTimeMessage: "whoops",
65
+ locale: locale,
66
+ timezone: timezone,
67
+ initialTimeForNewDate: initialTimeForNewDate
68
+ }));
69
+ expect(consoleError.mock.calls[0][2]).toContain(`Invalid prop \`initialTimeForNewDate\` \`${initialTimeForNewDate}\` supplied to \`DateTimeInput\`, expected a HH:MM formatted string.`);
70
+ const input = screen.getAllByRole('combobox')[0];
71
+ fireEvent.click(input);
72
+ const firstDay = screen.getByText('15');
73
+ await userEvent.click(firstDay);
74
+ expect(consoleError.mock.calls[1][0]).toBe(`Warning: [DateTimeInput] initialTimeForNewDate prop is not in the correct format. Please use HH:MM format.`);
75
+ });
76
+ it('should throw warning if initialTimeForNewDate prop hour and minute values are not in interval', async () => {
77
+ const locale = 'en-US';
78
+ const timezone = 'US/Eastern';
79
+ const consoleError = jest.spyOn(console, 'error').mockImplementation(() => {});
80
+ const initialTimeForNewDate = '99:99';
81
+ render( /*#__PURE__*/React.createElement(DateTimeInput, {
82
+ description: "date time",
83
+ prevMonthLabel: "Previous month",
84
+ nextMonthLabel: "Next month",
85
+ dateRenderLabel: "date",
86
+ timeRenderLabel: "time",
87
+ invalidDateTimeMessage: "whoops",
88
+ locale: locale,
89
+ timezone: timezone,
90
+ initialTimeForNewDate: initialTimeForNewDate
91
+ }));
92
+ const input = screen.getAllByRole('combobox')[0];
93
+ fireEvent.click(input);
94
+ const firstDay = screen.getByText('15');
95
+ await userEvent.click(firstDay);
96
+ expect(consoleError.mock.calls[0][0]).toContain(`Warning: [DateTimeInput] 0 <= hour < 24 and 0 <= minute < 60 for initialTimeForNewDate prop.`);
97
+ });
98
+
99
+ /*
100
+ * TODO write this test with Cypress
101
+ * Steps:
102
+ * 0. Set initialTimeForNewDate and defaultValue props -> check if defaultValue is rendered in the date input and time input fields
103
+ * 1. Clear date input field
104
+ * 2. Click on an area outside of the component
105
+ * 3. Check if time input field got cleared as well
106
+ * 4. Click on the date input and select a date
107
+ * 5. Observe if the time input has the value of initialTimeForNewDate
108
+ */
109
+
110
+ // it('should merge defaultValue and initialTimeForNewDate when the user clears date input', async () => {
111
+ // const locale = 'en-US'
112
+ // const timezone = 'US/Eastern'
113
+ //
114
+ // // const consoleWarn = jest.spyOn(console, 'warn').mockImplementation(() => {})
115
+ //
116
+ // const initialTimeForNewDate = '16:16'
117
+ // const defaultValue = '2018-01-18T13:30'
118
+ //
119
+ // const {container} = render(
120
+ // <DateTimeInput
121
+ // description="date time"
122
+ // prevMonthLabel="Previous month"
123
+ // nextMonthLabel="Next month"
124
+ // dateRenderLabel="date"
125
+ // timeRenderLabel="time"
126
+ // invalidDateTimeMessage="whoops"
127
+ // defaultValue={defaultValue}
128
+ // locale={locale}
129
+ // timezone={timezone}
130
+ // initialTimeForNewDate={initialTimeForNewDate}
131
+ // />
132
+ // )
133
+ //
134
+ // const dateInput = container.querySelector('input')
135
+ //
136
+ // const timeInput = container.querySelectorAll('input')[1]
137
+ //
138
+ // fireEvent.change(dateInput as Element, { target: { value: '' } })
139
+ //
140
+ //
141
+ // await waitFor(() => {
142
+ // fireEvent.keyDown(dateInput as Element, { key: 'Escape' })
143
+ //
144
+ // expect(timeInput).toHaveValue('')
145
+ // })
146
+ //
147
+ // // fireEvent.
148
+ // // fireEvent.change(timeInput as Element, { target: { value: '' } })
149
+ //
150
+ //
151
+ // const firstDay = screen.getByText('15')
152
+ //
153
+ // await userEvent.click(firstDay)
154
+ //
155
+ // const time = screen.getByText('4:16 PM')
156
+ //
157
+ // expect(time).toBeInTheDocument()
158
+ //
159
+ // // expect(consoleWarn.mock.calls[0][0]).toContain(
160
+ // // `Warning: [DateTimeInput] if defaultValue is set, initialTimeForNewDate will be ignored.`
161
+ // // )
162
+ // })
163
+
164
+ afterEach(() => {
165
+ jest.resetAllMocks();
166
+ });
167
+ });
@@ -34,6 +34,7 @@ import { AccessibleContent } from '@instructure/ui-a11y-content';
34
34
  import { IconButton } from '@instructure/ui-buttons';
35
35
  import { IconArrowOpenEndSolid, IconArrowOpenStartSolid } from '@instructure/ui-icons';
36
36
  import { propTypes, allowedProps } from './props';
37
+ import { error } from '@instructure/console';
37
38
 
38
39
  /**
39
40
  ---
@@ -209,6 +210,7 @@ let DateTimeInput = (_dec = testable(), _dec(_class = (_class2 = class DateTimeI
209
210
  if (dateStr) {
210
211
  const parsed = DateTime.parse(dateStr, this.locale(), this.timezone());
211
212
  if (parsed.isValid()) {
213
+ var _this$state;
212
214
  if (doNotChangeTime && this.state.timeSelectValue) {
213
215
  // There is a selected time, adjust the parsed date to its value
214
216
  const timeParsed = DateTime.parse(this.state.timeSelectValue, this.locale(), this.timezone());
@@ -217,6 +219,17 @@ let DateTimeInput = (_dec = testable(), _dec(_class = (_class2 = class DateTimeI
217
219
  if (doNotChangeDate && this.state.iso) {
218
220
  parsed.date(this.state.iso.date()).month(this.state.iso.month()).year(this.state.iso.year());
219
221
  }
222
+ if (this.props.initialTimeForNewDate && !((_this$state = this.state) !== null && _this$state !== void 0 && _this$state.timeSelectValue)) {
223
+ const hour = Number(this.props.initialTimeForNewDate.slice(0, 2));
224
+ const minute = Number(this.props.initialTimeForNewDate.slice(3, 5));
225
+ if (isNaN(hour) || isNaN(minute)) {
226
+ error(false, `[DateTimeInput] initialTimeForNewDate prop is not in the correct format. Please use HH:MM format.`);
227
+ } else if (hour < 0 || hour > 23 || minute > 59 || minute < 0) {
228
+ error(false, `[DateTimeInput] 0 <= hour < 24 and 0 <= minute < 60 for initialTimeForNewDate prop.`);
229
+ } else {
230
+ parsed.hour(hour).minute(minute);
231
+ }
232
+ }
220
233
  const newTimeSelectValue = parsed.toISOString();
221
234
  if (this.isDisabledDate(parsed)) {
222
235
  let text = typeof this.props.disabledDateTimeMessage === 'function' ? this.props.disabledDateTimeMessage(parsed.toISOString(true)) : this.props.disabledDateTimeMessage;
@@ -26,6 +26,15 @@ import { FormPropTypes } from '@instructure/ui-form-field';
26
26
  import { I18nPropTypes } from '@instructure/ui-i18n';
27
27
  import PropTypes from 'prop-types';
28
28
  import { controllable } from '@instructure/ui-prop-types';
29
+ const hourMinuteValidator = function (props, propName, componentName, location) {
30
+ const propValue = props[propName];
31
+ if (typeof propValue === 'undefined' || propValue === '') return null;
32
+ const hourMinuteRegex = /^\d{2}:\d{2}$/;
33
+ if (typeof propValue === 'string' && !propValue.match(hourMinuteRegex)) {
34
+ return new Error(`Invalid ${location} \`${propName}\` \`${propValue}\` supplied to \`${componentName}\`, expected ` + `a HH:MM formatted string.`);
35
+ }
36
+ return null;
37
+ };
29
38
  const propTypes = {
30
39
  description: PropTypes.node.isRequired,
31
40
  dateRenderLabel: PropTypes.oneOfType([PropTypes.func, PropTypes.node]).isRequired,
@@ -57,7 +66,8 @@ const propTypes = {
57
66
  onBlur: PropTypes.func,
58
67
  disabledDates: PropTypes.oneOfType([PropTypes.func, PropTypes.arrayOf(PropTypes.string)]),
59
68
  disabledDateTimeMessage: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
60
- allowNonStepInput: PropTypes.bool
69
+ allowNonStepInput: PropTypes.bool,
70
+ initialTimeForNewDate: hourMinuteValidator
61
71
  };
62
72
  const allowedProps = ['description', 'dateRenderLabel', 'prevMonthLabel', 'nextMonthLabel', 'datePlaceholder', 'timePlaceholder', 'dateFormat', 'interaction', 'timeRenderLabel', 'timeStep', 'timeFormat', 'locale', 'timezone', 'invalidDateTimeMessage', 'showMessages', 'messages', 'messageFormat', 'layout', 'rowSpacing', 'colSpacing', 'value', 'defaultValue', 'renderWeekdayLabels', 'isRequired', 'onChange', 'dateInputRef', 'timeInputRef', 'onBlur', 'disabledDates', 'disabledDateTimeMessage', 'allowNonStepInput'];
63
73
  export { propTypes, allowedProps };
@@ -0,0 +1,170 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
4
+ var _react = _interopRequireDefault(require("react"));
5
+ var _react2 = require("@testing-library/react");
6
+ require("@testing-library/jest-dom");
7
+ var _userEvent = require("@testing-library/user-event");
8
+ var _index = _interopRequireDefault(require("../index"));
9
+ /*
10
+ * The MIT License (MIT)
11
+ *
12
+ * Copyright (c) 2018 - present Instructure, Inc.
13
+ *
14
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
15
+ * of this software and associated documentation files (the "Software"), to deal
16
+ * in the Software without restriction, including without limitation the rights
17
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18
+ * copies of the Software, and to permit persons to whom the Software is
19
+ * furnished to do so, subject to the following conditions:
20
+ *
21
+ * The above copyright notice and this permission notice shall be included in all
22
+ * copies or substantial portions of the Software.
23
+ *
24
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30
+ * SOFTWARE.
31
+ */
32
+
33
+ describe('<DateTimeInput />', () => {
34
+ it("should change value of TimeSelect to initialTimeForNewDate prop's value", async () => {
35
+ const locale = 'en-US';
36
+ const timezone = 'US/Eastern';
37
+ (0, _react2.render)( /*#__PURE__*/_react.default.createElement(_index.default, {
38
+ description: "date time",
39
+ prevMonthLabel: "Previous month",
40
+ nextMonthLabel: "Next month",
41
+ dateRenderLabel: "date",
42
+ timeRenderLabel: "time",
43
+ invalidDateTimeMessage: "whoops",
44
+ locale: locale,
45
+ timezone: timezone,
46
+ initialTimeForNewDate: "05:05"
47
+ }));
48
+ const input = _react2.screen.getAllByRole('combobox')[0];
49
+ _react2.fireEvent.click(input);
50
+ const firstDay = _react2.screen.getByText('15');
51
+ await _userEvent.userEvent.click(firstDay);
52
+ const allInputs = _react2.screen.getAllByRole('combobox');
53
+ const targetInput = allInputs.find(input => input.value === '5:05 AM');
54
+ expect(targetInput).toBeInTheDocument();
55
+ });
56
+ it("should throw warning if initialTimeForNewDate prop's value is not HH:MM", async () => {
57
+ const locale = 'en-US';
58
+ const timezone = 'US/Eastern';
59
+ const consoleError = jest.spyOn(console, 'error').mockImplementation(() => {});
60
+ const initialTimeForNewDate = 'WRONG_FORMAT';
61
+ (0, _react2.render)( /*#__PURE__*/_react.default.createElement(_index.default, {
62
+ description: "date time",
63
+ prevMonthLabel: "Previous month",
64
+ nextMonthLabel: "Next month",
65
+ dateRenderLabel: "date",
66
+ timeRenderLabel: "time",
67
+ invalidDateTimeMessage: "whoops",
68
+ locale: locale,
69
+ timezone: timezone,
70
+ initialTimeForNewDate: initialTimeForNewDate
71
+ }));
72
+ expect(consoleError.mock.calls[0][2]).toContain(`Invalid prop \`initialTimeForNewDate\` \`${initialTimeForNewDate}\` supplied to \`DateTimeInput\`, expected a HH:MM formatted string.`);
73
+ const input = _react2.screen.getAllByRole('combobox')[0];
74
+ _react2.fireEvent.click(input);
75
+ const firstDay = _react2.screen.getByText('15');
76
+ await _userEvent.userEvent.click(firstDay);
77
+ expect(consoleError.mock.calls[1][0]).toBe(`Warning: [DateTimeInput] initialTimeForNewDate prop is not in the correct format. Please use HH:MM format.`);
78
+ });
79
+ it('should throw warning if initialTimeForNewDate prop hour and minute values are not in interval', async () => {
80
+ const locale = 'en-US';
81
+ const timezone = 'US/Eastern';
82
+ const consoleError = jest.spyOn(console, 'error').mockImplementation(() => {});
83
+ const initialTimeForNewDate = '99:99';
84
+ (0, _react2.render)( /*#__PURE__*/_react.default.createElement(_index.default, {
85
+ description: "date time",
86
+ prevMonthLabel: "Previous month",
87
+ nextMonthLabel: "Next month",
88
+ dateRenderLabel: "date",
89
+ timeRenderLabel: "time",
90
+ invalidDateTimeMessage: "whoops",
91
+ locale: locale,
92
+ timezone: timezone,
93
+ initialTimeForNewDate: initialTimeForNewDate
94
+ }));
95
+ const input = _react2.screen.getAllByRole('combobox')[0];
96
+ _react2.fireEvent.click(input);
97
+ const firstDay = _react2.screen.getByText('15');
98
+ await _userEvent.userEvent.click(firstDay);
99
+ expect(consoleError.mock.calls[0][0]).toContain(`Warning: [DateTimeInput] 0 <= hour < 24 and 0 <= minute < 60 for initialTimeForNewDate prop.`);
100
+ });
101
+
102
+ /*
103
+ * TODO write this test with Cypress
104
+ * Steps:
105
+ * 0. Set initialTimeForNewDate and defaultValue props -> check if defaultValue is rendered in the date input and time input fields
106
+ * 1. Clear date input field
107
+ * 2. Click on an area outside of the component
108
+ * 3. Check if time input field got cleared as well
109
+ * 4. Click on the date input and select a date
110
+ * 5. Observe if the time input has the value of initialTimeForNewDate
111
+ */
112
+
113
+ // it('should merge defaultValue and initialTimeForNewDate when the user clears date input', async () => {
114
+ // const locale = 'en-US'
115
+ // const timezone = 'US/Eastern'
116
+ //
117
+ // // const consoleWarn = jest.spyOn(console, 'warn').mockImplementation(() => {})
118
+ //
119
+ // const initialTimeForNewDate = '16:16'
120
+ // const defaultValue = '2018-01-18T13:30'
121
+ //
122
+ // const {container} = render(
123
+ // <DateTimeInput
124
+ // description="date time"
125
+ // prevMonthLabel="Previous month"
126
+ // nextMonthLabel="Next month"
127
+ // dateRenderLabel="date"
128
+ // timeRenderLabel="time"
129
+ // invalidDateTimeMessage="whoops"
130
+ // defaultValue={defaultValue}
131
+ // locale={locale}
132
+ // timezone={timezone}
133
+ // initialTimeForNewDate={initialTimeForNewDate}
134
+ // />
135
+ // )
136
+ //
137
+ // const dateInput = container.querySelector('input')
138
+ //
139
+ // const timeInput = container.querySelectorAll('input')[1]
140
+ //
141
+ // fireEvent.change(dateInput as Element, { target: { value: '' } })
142
+ //
143
+ //
144
+ // await waitFor(() => {
145
+ // fireEvent.keyDown(dateInput as Element, { key: 'Escape' })
146
+ //
147
+ // expect(timeInput).toHaveValue('')
148
+ // })
149
+ //
150
+ // // fireEvent.
151
+ // // fireEvent.change(timeInput as Element, { target: { value: '' } })
152
+ //
153
+ //
154
+ // const firstDay = screen.getByText('15')
155
+ //
156
+ // await userEvent.click(firstDay)
157
+ //
158
+ // const time = screen.getByText('4:16 PM')
159
+ //
160
+ // expect(time).toBeInTheDocument()
161
+ //
162
+ // // expect(consoleWarn.mock.calls[0][0]).toContain(
163
+ // // `Warning: [DateTimeInput] if defaultValue is set, initialTimeForNewDate will be ignored.`
164
+ // // )
165
+ // })
166
+
167
+ afterEach(() => {
168
+ jest.resetAllMocks();
169
+ });
170
+ });
@@ -19,6 +19,7 @@ var _IconButton = require("@instructure/ui-buttons/lib/IconButton");
19
19
  var _IconArrowOpenEndSolid = require("@instructure/ui-icons/lib/IconArrowOpenEndSolid.js");
20
20
  var _IconArrowOpenStartSolid = require("@instructure/ui-icons/lib/IconArrowOpenStartSolid.js");
21
21
  var _props = require("./props");
22
+ var _console = require("@instructure/console");
22
23
  var _dec, _class, _class2, _IconArrowOpenStartSo, _IconArrowOpenEndSoli;
23
24
  /*
24
25
  * The MIT License (MIT)
@@ -217,6 +218,7 @@ let DateTimeInput = exports.DateTimeInput = (_dec = (0, _testable.testable)(), _
217
218
  if (dateStr) {
218
219
  const parsed = _DateTime.DateTime.parse(dateStr, this.locale(), this.timezone());
219
220
  if (parsed.isValid()) {
221
+ var _this$state;
220
222
  if (doNotChangeTime && this.state.timeSelectValue) {
221
223
  // There is a selected time, adjust the parsed date to its value
222
224
  const timeParsed = _DateTime.DateTime.parse(this.state.timeSelectValue, this.locale(), this.timezone());
@@ -225,6 +227,17 @@ let DateTimeInput = exports.DateTimeInput = (_dec = (0, _testable.testable)(), _
225
227
  if (doNotChangeDate && this.state.iso) {
226
228
  parsed.date(this.state.iso.date()).month(this.state.iso.month()).year(this.state.iso.year());
227
229
  }
230
+ if (this.props.initialTimeForNewDate && !((_this$state = this.state) !== null && _this$state !== void 0 && _this$state.timeSelectValue)) {
231
+ const hour = Number(this.props.initialTimeForNewDate.slice(0, 2));
232
+ const minute = Number(this.props.initialTimeForNewDate.slice(3, 5));
233
+ if (isNaN(hour) || isNaN(minute)) {
234
+ (0, _console.error)(false, `[DateTimeInput] initialTimeForNewDate prop is not in the correct format. Please use HH:MM format.`);
235
+ } else if (hour < 0 || hour > 23 || minute > 59 || minute < 0) {
236
+ (0, _console.error)(false, `[DateTimeInput] 0 <= hour < 24 and 0 <= minute < 60 for initialTimeForNewDate prop.`);
237
+ } else {
238
+ parsed.hour(hour).minute(minute);
239
+ }
240
+ }
228
241
  const newTimeSelectValue = parsed.toISOString();
229
242
  if (this.isDisabledDate(parsed)) {
230
243
  let text = typeof this.props.disabledDateTimeMessage === 'function' ? this.props.disabledDateTimeMessage(parsed.toISOString(true)) : this.props.disabledDateTimeMessage;
@@ -33,6 +33,15 @@ var _controllable = require("@instructure/ui-prop-types/lib/controllable.js");
33
33
  * SOFTWARE.
34
34
  */
35
35
 
36
+ const hourMinuteValidator = function (props, propName, componentName, location) {
37
+ const propValue = props[propName];
38
+ if (typeof propValue === 'undefined' || propValue === '') return null;
39
+ const hourMinuteRegex = /^\d{2}:\d{2}$/;
40
+ if (typeof propValue === 'string' && !propValue.match(hourMinuteRegex)) {
41
+ return new Error(`Invalid ${location} \`${propName}\` \`${propValue}\` supplied to \`${componentName}\`, expected ` + `a HH:MM formatted string.`);
42
+ }
43
+ return null;
44
+ };
36
45
  const propTypes = exports.propTypes = {
37
46
  description: _propTypes.default.node.isRequired,
38
47
  dateRenderLabel: _propTypes.default.oneOfType([_propTypes.default.func, _propTypes.default.node]).isRequired,
@@ -64,6 +73,7 @@ const propTypes = exports.propTypes = {
64
73
  onBlur: _propTypes.default.func,
65
74
  disabledDates: _propTypes.default.oneOfType([_propTypes.default.func, _propTypes.default.arrayOf(_propTypes.default.string)]),
66
75
  disabledDateTimeMessage: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.func]),
67
- allowNonStepInput: _propTypes.default.bool
76
+ allowNonStepInput: _propTypes.default.bool,
77
+ initialTimeForNewDate: hourMinuteValidator
68
78
  };
69
79
  const allowedProps = exports.allowedProps = ['description', 'dateRenderLabel', 'prevMonthLabel', 'nextMonthLabel', 'datePlaceholder', 'timePlaceholder', 'dateFormat', 'interaction', 'timeRenderLabel', 'timeStep', 'timeFormat', 'locale', 'timezone', 'invalidDateTimeMessage', 'showMessages', 'messages', 'messageFormat', 'layout', 'rowSpacing', 'colSpacing', 'value', 'defaultValue', 'renderWeekdayLabels', 'isRequired', 'onChange', 'dateInputRef', 'timeInputRef', 'onBlur', 'disabledDates', 'disabledDateTimeMessage', 'allowNonStepInput'];