@instructure/ui-date-time-input 8.52.1-snapshot-7 → 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 +6 -91
- package/es/DateTimeInput/__new-tests__/DateTimeInput.test.js +167 -0
- package/es/DateTimeInput/index.js +13 -4
- package/es/DateTimeInput/props.js +11 -1
- package/lib/DateTimeInput/__new-tests__/DateTimeInput.test.js +170 -0
- package/lib/DateTimeInput/index.js +13 -4
- package/lib/DateTimeInput/props.js +11 -1
- package/package.json +22 -18
- package/src/DateTimeInput/__new-tests__/DateTimeInput.test.tsx +211 -0
- package/src/DateTimeInput/index.tsx +18 -4
- package/src/DateTimeInput/props.ts +28 -2
- package/tsconfig.build.json +2 -1
- package/tsconfig.build.tsbuildinfo +1 -1
- package/types/DateTimeInput/__new-tests__/DateTimeInput.test.d.ts +2 -0
- package/types/DateTimeInput/__new-tests__/DateTimeInput.test.d.ts.map +1 -0
- package/types/DateTimeInput/index.d.ts +1 -1
- package/types/DateTimeInput/index.d.ts.map +1 -1
- package/types/DateTimeInput/props.d.ts +5 -0
- package/types/DateTimeInput/props.d.ts.map +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,183 +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
|
-
|
|
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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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))
|
|
16
13
|
|
|
17
14
|
# [8.52.0](https://github.com/instructure/instructure-ui/compare/v8.51.0...v8.52.0) (2024-02-02)
|
|
18
15
|
|
|
19
16
|
**Note:** Version bump only for package @instructure/ui-date-time-input
|
|
20
17
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
18
|
# [8.51.0](https://github.com/instructure/instructure-ui/compare/v8.50.0...v8.51.0) (2023-12-14)
|
|
26
19
|
|
|
27
|
-
|
|
28
20
|
### Features
|
|
29
21
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
22
|
+
- **ui-date-time-input:** add showMessages prop ([5212a19](https://github.com/instructure/instructure-ui/commit/5212a192b56fed621c80a697579fc164f9592391))
|
|
35
23
|
|
|
36
24
|
# [8.50.0](https://github.com/instructure/instructure-ui/compare/v8.49.0...v8.50.0) (2023-12-05)
|
|
37
25
|
|
|
38
26
|
**Note:** Version bump only for package @instructure/ui-date-time-input
|
|
39
27
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
28
|
# [8.49.0](https://github.com/instructure/instructure-ui/compare/v8.48.3...v8.49.0) (2023-11-24)
|
|
45
29
|
|
|
46
30
|
**Note:** Version bump only for package @instructure/ui-date-time-input
|
|
47
31
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
32
|
## [8.48.3](https://github.com/instructure/instructure-ui/compare/v8.48.2...v8.48.3) (2023-11-23)
|
|
53
33
|
|
|
54
34
|
**Note:** Version bump only for package @instructure/ui-date-time-input
|
|
55
35
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
36
|
## [8.48.2](https://github.com/instructure/instructure-ui/compare/v8.48.1...v8.48.2) (2023-11-21)
|
|
61
37
|
|
|
62
38
|
**Note:** Version bump only for package @instructure/ui-date-time-input
|
|
63
39
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
40
|
## [8.48.1](https://github.com/instructure/instructure-ui/compare/v8.48.0...v8.48.1) (2023-11-17)
|
|
69
41
|
|
|
70
42
|
**Note:** Version bump only for package @instructure/ui-date-time-input
|
|
71
43
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
44
|
# [8.48.0](https://github.com/instructure/instructure-ui/compare/v8.47.1...v8.48.0) (2023-11-10)
|
|
77
45
|
|
|
78
46
|
**Note:** Version bump only for package @instructure/ui-date-time-input
|
|
79
47
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
48
|
## [8.47.1](https://github.com/instructure/instructure-ui/compare/v8.47.0...v8.47.1) (2023-11-06)
|
|
85
49
|
|
|
86
50
|
**Note:** Version bump only for package @instructure/ui-date-time-input
|
|
87
51
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
52
|
# [8.47.0](https://github.com/instructure/instructure-ui/compare/v8.46.1...v8.47.0) (2023-10-27)
|
|
93
53
|
|
|
94
|
-
|
|
95
54
|
### Bug Fixes
|
|
96
55
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
56
|
+
- **ui-date-time-input:** clear TimeSelect value when DateInput value is cleared ([b1a58e5](https://github.com/instructure/instructure-ui/commit/b1a58e5c04822da491966bc0a79403b30749ff7e))
|
|
102
57
|
|
|
103
58
|
## [8.46.1](https://github.com/instructure/instructure-ui/compare/v8.46.0...v8.46.1) (2023-10-13)
|
|
104
59
|
|
|
105
60
|
**Note:** Version bump only for package @instructure/ui-date-time-input
|
|
106
61
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
62
|
# [8.46.0](https://github.com/instructure/instructure-ui/compare/v8.45.0...v8.46.0) (2023-10-11)
|
|
112
63
|
|
|
113
64
|
**Note:** Version bump only for package @instructure/ui-date-time-input
|
|
114
65
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
66
|
# [8.45.0](https://github.com/instructure/instructure-ui/compare/v8.44.0...v8.45.0) (2023-10-03)
|
|
120
67
|
|
|
121
68
|
**Note:** Version bump only for package @instructure/ui-date-time-input
|
|
122
69
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
70
|
# [8.44.0](https://github.com/instructure/instructure-ui/compare/v8.43.1...v8.44.0) (2023-09-21)
|
|
128
71
|
|
|
129
72
|
**Note:** Version bump only for package @instructure/ui-date-time-input
|
|
130
73
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
74
|
## [8.43.1](https://github.com/instructure/instructure-ui/compare/v8.43.0...v8.43.1) (2023-09-11)
|
|
136
75
|
|
|
137
76
|
**Note:** Version bump only for package @instructure/ui-date-time-input
|
|
138
77
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
78
|
# [8.43.0](https://github.com/instructure/instructure-ui/compare/v8.41.1...v8.43.0) (2023-09-07)
|
|
144
79
|
|
|
145
80
|
**Note:** Version bump only for package @instructure/ui-date-time-input
|
|
146
81
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
82
|
# [8.42.0](https://github.com/instructure/instructure-ui/compare/v8.41.1...v8.42.0) (2023-09-07)
|
|
152
83
|
|
|
153
84
|
**Note:** Version bump only for package @instructure/ui-date-time-input
|
|
154
85
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
86
|
## [8.41.1](https://github.com/instructure/instructure-ui/compare/v8.41.0...v8.41.1) (2023-08-24)
|
|
160
87
|
|
|
161
88
|
**Note:** Version bump only for package @instructure/ui-date-time-input
|
|
162
89
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
90
|
# [8.41.0](https://github.com/instructure/instructure-ui/compare/v8.40.1...v8.41.0) (2023-08-21)
|
|
168
91
|
|
|
169
92
|
**Note:** Version bump only for package @instructure/ui-date-time-input
|
|
170
93
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
94
|
## [8.40.1](https://github.com/instructure/instructure-ui/compare/v8.40.0...v8.40.1) (2023-08-18)
|
|
176
95
|
|
|
177
96
|
**Note:** Version bump only for package @instructure/ui-date-time-input
|
|
178
97
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
98
|
# [8.40.0](https://github.com/instructure/instructure-ui/compare/v8.39.0...v8.40.0) (2023-08-17)
|
|
184
99
|
|
|
185
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;
|
|
@@ -322,10 +335,6 @@ let DateTimeInput = (_dec = testable(), _dec(_class = (_class2 = class DateTimeI
|
|
|
322
335
|
this.changeStateIfNeeded(newState, event);
|
|
323
336
|
}
|
|
324
337
|
renderDays() {
|
|
325
|
-
if (!this.state.isShowingCalendar) {
|
|
326
|
-
// this is an expensive function, only execute if the calendar is open
|
|
327
|
-
return;
|
|
328
|
-
}
|
|
329
338
|
const renderedDate = this.state.renderedDate;
|
|
330
339
|
// Sets it to the first local day of the week counting back from the start of the month.
|
|
331
340
|
// Note that first day depends on the locale, e.g. it's Sunday in the US and
|
|
@@ -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;
|
|
@@ -330,10 +343,6 @@ let DateTimeInput = exports.DateTimeInput = (_dec = (0, _testable.testable)(), _
|
|
|
330
343
|
this.changeStateIfNeeded(newState, event);
|
|
331
344
|
}
|
|
332
345
|
renderDays() {
|
|
333
|
-
if (!this.state.isShowingCalendar) {
|
|
334
|
-
// this is an expensive function, only execute if the calendar is open
|
|
335
|
-
return;
|
|
336
|
-
}
|
|
337
346
|
const renderedDate = this.state.renderedDate;
|
|
338
347
|
// Sets it to the first local day of the week counting back from the start of the month.
|
|
339
348
|
// Note that first day depends on the locale, e.g. it's Sunday in the US and
|
|
@@ -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'];
|