@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 +6 -92
- package/es/DateTimeInput/__new-tests__/DateTimeInput.test.js +167 -0
- package/es/DateTimeInput/index.js +13 -0
- package/es/DateTimeInput/props.js +11 -1
- package/lib/DateTimeInput/__new-tests__/DateTimeInput.test.js +170 -0
- package/lib/DateTimeInput/index.js +13 -0
- 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 -0
- 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.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,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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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'];
|