@instructure/ui-date-time-input 8.52.1-snapshot-11 → 8.53.1-snapshot-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 +10 -88
- 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,106 @@
|
|
|
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.
|
|
6
|
+
## [8.53.1-snapshot-0](https://github.com/instructure/instructure-ui/compare/v8.53.0...v8.53.1-snapshot-0) (2024-02-08)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @instructure/ui-date-time-input
|
|
7
9
|
|
|
8
10
|
|
|
9
|
-
### Features
|
|
10
11
|
|
|
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
12
|
|
|
14
13
|
|
|
14
|
+
# [8.53.0](https://github.com/instructure/instructure-ui/compare/v8.52.0...v8.53.0) (2024-02-08)
|
|
15
15
|
|
|
16
|
+
### Features
|
|
16
17
|
|
|
18
|
+
- **many:** provide defaults to dateInput for easier setup and use ([dcefc4e](https://github.com/instructure/instructure-ui/commit/dcefc4e259118264d76dfd248b01682a7c2ef661))
|
|
19
|
+
- **ui-date-time-input:** add initialTimeForNewDate prop to datetimeinput ([33711a3](https://github.com/instructure/instructure-ui/commit/33711a3d899c34913aafd40c7dec90faabc88cd0))
|
|
20
|
+
- **ui-date-time-input:** add placeholder to datetimeinput's timeselect ([3ec8cc3](https://github.com/instructure/instructure-ui/commit/3ec8cc31f06ee570b704f88b09739a0868da9ff7))
|
|
17
21
|
|
|
18
22
|
# [8.52.0](https://github.com/instructure/instructure-ui/compare/v8.51.0...v8.52.0) (2024-02-02)
|
|
19
23
|
|
|
20
24
|
**Note:** Version bump only for package @instructure/ui-date-time-input
|
|
21
25
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
26
|
# [8.51.0](https://github.com/instructure/instructure-ui/compare/v8.50.0...v8.51.0) (2023-12-14)
|
|
27
27
|
|
|
28
|
-
|
|
29
28
|
### Features
|
|
30
29
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
30
|
+
- **ui-date-time-input:** add showMessages prop ([5212a19](https://github.com/instructure/instructure-ui/commit/5212a192b56fed621c80a697579fc164f9592391))
|
|
36
31
|
|
|
37
32
|
# [8.50.0](https://github.com/instructure/instructure-ui/compare/v8.49.0...v8.50.0) (2023-12-05)
|
|
38
33
|
|
|
39
34
|
**Note:** Version bump only for package @instructure/ui-date-time-input
|
|
40
35
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
36
|
# [8.49.0](https://github.com/instructure/instructure-ui/compare/v8.48.3...v8.49.0) (2023-11-24)
|
|
46
37
|
|
|
47
38
|
**Note:** Version bump only for package @instructure/ui-date-time-input
|
|
48
39
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
40
|
## [8.48.3](https://github.com/instructure/instructure-ui/compare/v8.48.2...v8.48.3) (2023-11-23)
|
|
54
41
|
|
|
55
42
|
**Note:** Version bump only for package @instructure/ui-date-time-input
|
|
56
43
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
44
|
## [8.48.2](https://github.com/instructure/instructure-ui/compare/v8.48.1...v8.48.2) (2023-11-21)
|
|
62
45
|
|
|
63
46
|
**Note:** Version bump only for package @instructure/ui-date-time-input
|
|
64
47
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
48
|
## [8.48.1](https://github.com/instructure/instructure-ui/compare/v8.48.0...v8.48.1) (2023-11-17)
|
|
70
49
|
|
|
71
50
|
**Note:** Version bump only for package @instructure/ui-date-time-input
|
|
72
51
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
52
|
# [8.48.0](https://github.com/instructure/instructure-ui/compare/v8.47.1...v8.48.0) (2023-11-10)
|
|
78
53
|
|
|
79
54
|
**Note:** Version bump only for package @instructure/ui-date-time-input
|
|
80
55
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
56
|
## [8.47.1](https://github.com/instructure/instructure-ui/compare/v8.47.0...v8.47.1) (2023-11-06)
|
|
86
57
|
|
|
87
58
|
**Note:** Version bump only for package @instructure/ui-date-time-input
|
|
88
59
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
60
|
# [8.47.0](https://github.com/instructure/instructure-ui/compare/v8.46.1...v8.47.0) (2023-10-27)
|
|
94
61
|
|
|
95
|
-
|
|
96
62
|
### Bug Fixes
|
|
97
63
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
64
|
+
- **ui-date-time-input:** clear TimeSelect value when DateInput value is cleared ([b1a58e5](https://github.com/instructure/instructure-ui/commit/b1a58e5c04822da491966bc0a79403b30749ff7e))
|
|
103
65
|
|
|
104
66
|
## [8.46.1](https://github.com/instructure/instructure-ui/compare/v8.46.0...v8.46.1) (2023-10-13)
|
|
105
67
|
|
|
106
68
|
**Note:** Version bump only for package @instructure/ui-date-time-input
|
|
107
69
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
70
|
# [8.46.0](https://github.com/instructure/instructure-ui/compare/v8.45.0...v8.46.0) (2023-10-11)
|
|
113
71
|
|
|
114
72
|
**Note:** Version bump only for package @instructure/ui-date-time-input
|
|
115
73
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
74
|
# [8.45.0](https://github.com/instructure/instructure-ui/compare/v8.44.0...v8.45.0) (2023-10-03)
|
|
121
75
|
|
|
122
76
|
**Note:** Version bump only for package @instructure/ui-date-time-input
|
|
123
77
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
78
|
# [8.44.0](https://github.com/instructure/instructure-ui/compare/v8.43.1...v8.44.0) (2023-09-21)
|
|
129
79
|
|
|
130
80
|
**Note:** Version bump only for package @instructure/ui-date-time-input
|
|
131
81
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
82
|
## [8.43.1](https://github.com/instructure/instructure-ui/compare/v8.43.0...v8.43.1) (2023-09-11)
|
|
137
83
|
|
|
138
84
|
**Note:** Version bump only for package @instructure/ui-date-time-input
|
|
139
85
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
86
|
# [8.43.0](https://github.com/instructure/instructure-ui/compare/v8.41.1...v8.43.0) (2023-09-07)
|
|
145
87
|
|
|
146
88
|
**Note:** Version bump only for package @instructure/ui-date-time-input
|
|
147
89
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
90
|
# [8.42.0](https://github.com/instructure/instructure-ui/compare/v8.41.1...v8.42.0) (2023-09-07)
|
|
153
91
|
|
|
154
92
|
**Note:** Version bump only for package @instructure/ui-date-time-input
|
|
155
93
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
94
|
## [8.41.1](https://github.com/instructure/instructure-ui/compare/v8.41.0...v8.41.1) (2023-08-24)
|
|
161
95
|
|
|
162
96
|
**Note:** Version bump only for package @instructure/ui-date-time-input
|
|
163
97
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
98
|
# [8.41.0](https://github.com/instructure/instructure-ui/compare/v8.40.1...v8.41.0) (2023-08-21)
|
|
169
99
|
|
|
170
100
|
**Note:** Version bump only for package @instructure/ui-date-time-input
|
|
171
101
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
102
|
## [8.40.1](https://github.com/instructure/instructure-ui/compare/v8.40.0...v8.40.1) (2023-08-18)
|
|
177
103
|
|
|
178
104
|
**Note:** Version bump only for package @instructure/ui-date-time-input
|
|
179
105
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
106
|
# [8.40.0](https://github.com/instructure/instructure-ui/compare/v8.39.0...v8.40.0) (2023-08-17)
|
|
185
107
|
|
|
186
108
|
**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'];
|