@instructure/ui-date-input 9.5.2-snapshot-7 → 9.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -2
- package/es/DateInput2/index.js +22 -17
- package/lib/DateInput2/index.js +22 -17
- package/package.json +20 -20
- package/src/DateInput2/index.tsx +35 -41
- package/src/DateInput2/props.ts +10 -4
- package/src/index.ts +1 -0
- package/tsconfig.build.tsbuildinfo +1 -1
- package/types/DateInput2/index.d.ts +38 -1
- package/types/DateInput2/index.d.ts.map +1 -1
- package/types/DateInput2/props.d.ts +5 -4
- package/types/DateInput2/props.d.ts.map +1 -1
- package/types/index.d.ts +1 -0
- package/types/index.d.ts.map +1 -1
package/CHANGELOG.md
CHANGED
@@ -3,9 +3,12 @@
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
5
5
|
|
6
|
-
## [9.5.2
|
6
|
+
## [9.5.2](https://github.com/instructure/instructure-ui/compare/v9.5.1...v9.5.2) (2024-08-05)
|
7
7
|
|
8
|
-
|
8
|
+
|
9
|
+
### Bug Fixes
|
10
|
+
|
11
|
+
* **ui-calendar,ui-date-input:** fix year picker for non latin based locales; return iso date string in onRequestValidateDate ([d7df0e8](https://github.com/instructure/instructure-ui/commit/d7df0e8d9fc0656e877bd243d9858dc3e5a47198))
|
9
12
|
|
10
13
|
|
11
14
|
|
package/es/DateInput2/index.js
CHANGED
@@ -26,7 +26,6 @@ var _IconCalendarMonthLin, _IconArrowOpenEndSoli, _IconArrowOpenStartSo;
|
|
26
26
|
|
27
27
|
/** @jsx jsx */
|
28
28
|
import { useState, useEffect, useContext } from 'react';
|
29
|
-
import moment from 'moment-timezone';
|
30
29
|
import { Calendar } from '@instructure/ui-calendar';
|
31
30
|
import { IconButton } from '@instructure/ui-buttons';
|
32
31
|
import { IconCalendarMonthLine, IconArrowOpenEndSolid, IconArrowOpenStartSolid } from '@instructure/ui-icons';
|
@@ -36,11 +35,10 @@ import { passthroughProps } from '@instructure/ui-react-utils';
|
|
36
35
|
import { ApplyLocaleContext, Locale } from '@instructure/ui-i18n';
|
37
36
|
import { jsx } from '@instructure/emotion';
|
38
37
|
import { propTypes } from './props';
|
39
|
-
function
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
return moment.tz(dateString, [moment.ISO_8601, 'llll', 'LLLL', 'lll', 'LLL', 'll', 'LL', 'l', 'L'], locale, true, timezone).isValid();
|
38
|
+
function parseDate(dateString) {
|
39
|
+
const date = new Date(dateString);
|
40
|
+
// return empty string if not a valid date
|
41
|
+
return isNaN(date.getTime()) ? '' : date.toISOString();
|
44
42
|
}
|
45
43
|
|
46
44
|
/**
|
@@ -82,6 +80,8 @@ const DateInput2 = ({
|
|
82
80
|
setShowPopover = _useState6[1];
|
83
81
|
const localeContext = useContext(ApplyLocaleContext);
|
84
82
|
useEffect(() => {
|
83
|
+
// when `value` is changed, validation runs again and removes the error message if validation passes
|
84
|
+
// but it's NOT adding error message if validation fails for better UX
|
85
85
|
validateInput(true);
|
86
86
|
}, [value]);
|
87
87
|
useEffect(() => {
|
@@ -89,6 +89,10 @@ const DateInput2 = ({
|
|
89
89
|
}, [messages]);
|
90
90
|
const handleInputChange = (e, value) => {
|
91
91
|
onChange === null || onChange === void 0 ? void 0 : onChange(e, value);
|
92
|
+
// blur event formats the input which should trigger parsing
|
93
|
+
if (e.type !== 'blur') {
|
94
|
+
setSelectedDate(parseDate(value));
|
95
|
+
}
|
92
96
|
};
|
93
97
|
const handleDateSelected = (dateString, _momentDate, e) => {
|
94
98
|
const formattedDate = new Date(dateString).toLocaleDateString(getLocale(), {
|
@@ -98,23 +102,24 @@ const DateInput2 = ({
|
|
98
102
|
timeZone: getTimezone()
|
99
103
|
});
|
100
104
|
handleInputChange(e, formattedDate);
|
105
|
+
setSelectedDate(dateString);
|
101
106
|
setShowPopover(false);
|
102
|
-
onRequestValidateDate === null || onRequestValidateDate === void 0 ? void 0 : onRequestValidateDate(
|
107
|
+
onRequestValidateDate === null || onRequestValidateDate === void 0 ? void 0 : onRequestValidateDate(dateString, true);
|
103
108
|
};
|
109
|
+
|
110
|
+
// onlyRemoveError is used to remove the error msg immediately when the user inputs a valid date (and don't wait for blur event)
|
104
111
|
const validateInput = (onlyRemoveError = false) => {
|
105
|
-
//
|
106
|
-
|
107
|
-
// otherwise DateInput could pass invalid dates to Calendar and break it
|
108
|
-
if (isValidDate(value || '') && isValidMomentDate(value || '', getLocale(), getTimezone()) || value === '') {
|
109
|
-
setSelectedDate(value || '');
|
112
|
+
// don't validate empty input
|
113
|
+
if (!value || parseDate(value) || selectedDate) {
|
110
114
|
setInputMessages(messages || []);
|
111
115
|
return true;
|
112
116
|
}
|
113
|
-
if
|
114
|
-
|
117
|
+
// only show error if there is no user provided validation callback
|
118
|
+
if (!onlyRemoveError && typeof invalidDateErrorMessage === 'string' && !onRequestValidateDate) {
|
119
|
+
setInputMessages([{
|
115
120
|
type: 'error',
|
116
121
|
text: invalidDateErrorMessage
|
117
|
-
}
|
122
|
+
}]);
|
118
123
|
}
|
119
124
|
return false;
|
120
125
|
};
|
@@ -137,8 +142,8 @@ const DateInput2 = ({
|
|
137
142
|
};
|
138
143
|
const handleBlur = e => {
|
139
144
|
const isInputValid = validateInput(false);
|
140
|
-
if (isInputValid &&
|
141
|
-
const formattedDate = new Date(
|
145
|
+
if (isInputValid && selectedDate) {
|
146
|
+
const formattedDate = new Date(selectedDate).toLocaleDateString(getLocale(), {
|
142
147
|
month: 'long',
|
143
148
|
year: 'numeric',
|
144
149
|
day: 'numeric',
|
package/lib/DateInput2/index.js
CHANGED
@@ -7,7 +7,6 @@ Object.defineProperty(exports, "__esModule", {
|
|
7
7
|
exports.default = exports.DateInput2 = void 0;
|
8
8
|
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
|
9
9
|
var _react = require("react");
|
10
|
-
var _momentTimezone = _interopRequireDefault(require("moment-timezone"));
|
11
10
|
var _Calendar = require("@instructure/ui-calendar/lib/Calendar");
|
12
11
|
var _IconButton = require("@instructure/ui-buttons/lib/IconButton");
|
13
12
|
var _IconCalendarMonthLine = require("@instructure/ui-icons/lib/IconCalendarMonthLine.js");
|
@@ -45,11 +44,10 @@ var _IconCalendarMonthLin, _IconArrowOpenEndSoli, _IconArrowOpenStartSo;
|
|
45
44
|
* SOFTWARE.
|
46
45
|
*/
|
47
46
|
/** @jsx jsx */
|
48
|
-
function
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
return _momentTimezone.default.tz(dateString, [_momentTimezone.default.ISO_8601, 'llll', 'LLLL', 'lll', 'LLL', 'll', 'LL', 'l', 'L'], locale, true, timezone).isValid();
|
47
|
+
function parseDate(dateString) {
|
48
|
+
const date = new Date(dateString);
|
49
|
+
// return empty string if not a valid date
|
50
|
+
return isNaN(date.getTime()) ? '' : date.toISOString();
|
53
51
|
}
|
54
52
|
|
55
53
|
/**
|
@@ -91,6 +89,8 @@ const DateInput2 = ({
|
|
91
89
|
setShowPopover = _useState6[1];
|
92
90
|
const localeContext = (0, _react.useContext)(_ApplyLocaleContext.ApplyLocaleContext);
|
93
91
|
(0, _react.useEffect)(() => {
|
92
|
+
// when `value` is changed, validation runs again and removes the error message if validation passes
|
93
|
+
// but it's NOT adding error message if validation fails for better UX
|
94
94
|
validateInput(true);
|
95
95
|
}, [value]);
|
96
96
|
(0, _react.useEffect)(() => {
|
@@ -98,6 +98,10 @@ const DateInput2 = ({
|
|
98
98
|
}, [messages]);
|
99
99
|
const handleInputChange = (e, value) => {
|
100
100
|
onChange === null || onChange === void 0 ? void 0 : onChange(e, value);
|
101
|
+
// blur event formats the input which should trigger parsing
|
102
|
+
if (e.type !== 'blur') {
|
103
|
+
setSelectedDate(parseDate(value));
|
104
|
+
}
|
101
105
|
};
|
102
106
|
const handleDateSelected = (dateString, _momentDate, e) => {
|
103
107
|
const formattedDate = new Date(dateString).toLocaleDateString(getLocale(), {
|
@@ -107,23 +111,24 @@ const DateInput2 = ({
|
|
107
111
|
timeZone: getTimezone()
|
108
112
|
});
|
109
113
|
handleInputChange(e, formattedDate);
|
114
|
+
setSelectedDate(dateString);
|
110
115
|
setShowPopover(false);
|
111
|
-
onRequestValidateDate === null || onRequestValidateDate === void 0 ? void 0 : onRequestValidateDate(
|
116
|
+
onRequestValidateDate === null || onRequestValidateDate === void 0 ? void 0 : onRequestValidateDate(dateString, true);
|
112
117
|
};
|
118
|
+
|
119
|
+
// onlyRemoveError is used to remove the error msg immediately when the user inputs a valid date (and don't wait for blur event)
|
113
120
|
const validateInput = (onlyRemoveError = false) => {
|
114
|
-
//
|
115
|
-
|
116
|
-
// otherwise DateInput could pass invalid dates to Calendar and break it
|
117
|
-
if (isValidDate(value || '') && isValidMomentDate(value || '', getLocale(), getTimezone()) || value === '') {
|
118
|
-
setSelectedDate(value || '');
|
121
|
+
// don't validate empty input
|
122
|
+
if (!value || parseDate(value) || selectedDate) {
|
119
123
|
setInputMessages(messages || []);
|
120
124
|
return true;
|
121
125
|
}
|
122
|
-
if
|
123
|
-
|
126
|
+
// only show error if there is no user provided validation callback
|
127
|
+
if (!onlyRemoveError && typeof invalidDateErrorMessage === 'string' && !onRequestValidateDate) {
|
128
|
+
setInputMessages([{
|
124
129
|
type: 'error',
|
125
130
|
text: invalidDateErrorMessage
|
126
|
-
}
|
131
|
+
}]);
|
127
132
|
}
|
128
133
|
return false;
|
129
134
|
};
|
@@ -146,8 +151,8 @@ const DateInput2 = ({
|
|
146
151
|
};
|
147
152
|
const handleBlur = e => {
|
148
153
|
const isInputValid = validateInput(false);
|
149
|
-
if (isInputValid &&
|
150
|
-
const formattedDate = new Date(
|
154
|
+
if (isInputValid && selectedDate) {
|
155
|
+
const formattedDate = new Date(selectedDate).toLocaleDateString(getLocale(), {
|
151
156
|
month: 'long',
|
152
157
|
year: 'numeric',
|
153
158
|
day: 'numeric',
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@instructure/ui-date-input",
|
3
|
-
"version": "9.5.2
|
3
|
+
"version": "9.5.2",
|
4
4
|
"description": "A UI component library made by Instructure Inc.",
|
5
5
|
"author": "Instructure, Inc. Engineering and Product Design",
|
6
6
|
"module": "./es/index.js",
|
@@ -23,11 +23,11 @@
|
|
23
23
|
},
|
24
24
|
"license": "MIT",
|
25
25
|
"devDependencies": {
|
26
|
-
"@instructure/ui-axe-check": "9.5.2
|
27
|
-
"@instructure/ui-babel-preset": "9.5.2
|
28
|
-
"@instructure/ui-buttons": "9.5.2
|
29
|
-
"@instructure/ui-scripts": "9.5.2
|
30
|
-
"@instructure/ui-test-utils": "9.5.2
|
26
|
+
"@instructure/ui-axe-check": "9.5.2",
|
27
|
+
"@instructure/ui-babel-preset": "9.5.2",
|
28
|
+
"@instructure/ui-buttons": "9.5.2",
|
29
|
+
"@instructure/ui-scripts": "9.5.2",
|
30
|
+
"@instructure/ui-test-utils": "9.5.2",
|
31
31
|
"@testing-library/jest-dom": "^6.4.6",
|
32
32
|
"@testing-library/react": "^15.0.7",
|
33
33
|
"@testing-library/user-event": "^14.5.2",
|
@@ -35,20 +35,20 @@
|
|
35
35
|
},
|
36
36
|
"dependencies": {
|
37
37
|
"@babel/runtime": "^7.24.5",
|
38
|
-
"@instructure/emotion": "9.5.2
|
39
|
-
"@instructure/shared-types": "9.5.2
|
40
|
-
"@instructure/ui-calendar": "9.5.2
|
41
|
-
"@instructure/ui-form-field": "9.5.2
|
42
|
-
"@instructure/ui-i18n": "9.5.2
|
43
|
-
"@instructure/ui-icons": "9.5.2
|
44
|
-
"@instructure/ui-popover": "9.5.2
|
45
|
-
"@instructure/ui-position": "9.5.2
|
46
|
-
"@instructure/ui-prop-types": "9.5.2
|
47
|
-
"@instructure/ui-react-utils": "9.5.2
|
48
|
-
"@instructure/ui-selectable": "9.5.2
|
49
|
-
"@instructure/ui-testable": "9.5.2
|
50
|
-
"@instructure/ui-text-input": "9.5.2
|
51
|
-
"@instructure/ui-utils": "9.5.2
|
38
|
+
"@instructure/emotion": "9.5.2",
|
39
|
+
"@instructure/shared-types": "9.5.2",
|
40
|
+
"@instructure/ui-calendar": "9.5.2",
|
41
|
+
"@instructure/ui-form-field": "9.5.2",
|
42
|
+
"@instructure/ui-i18n": "9.5.2",
|
43
|
+
"@instructure/ui-icons": "9.5.2",
|
44
|
+
"@instructure/ui-popover": "9.5.2",
|
45
|
+
"@instructure/ui-position": "9.5.2",
|
46
|
+
"@instructure/ui-prop-types": "9.5.2",
|
47
|
+
"@instructure/ui-react-utils": "9.5.2",
|
48
|
+
"@instructure/ui-selectable": "9.5.2",
|
49
|
+
"@instructure/ui-testable": "9.5.2",
|
50
|
+
"@instructure/ui-text-input": "9.5.2",
|
51
|
+
"@instructure/ui-utils": "9.5.2",
|
52
52
|
"moment-timezone": "^0.5.45",
|
53
53
|
"prop-types": "^15.8.1"
|
54
54
|
},
|
package/src/DateInput2/index.tsx
CHANGED
@@ -25,7 +25,6 @@
|
|
25
25
|
/** @jsx jsx */
|
26
26
|
import { useState, useEffect, useContext } from 'react'
|
27
27
|
import type { SyntheticEvent } from 'react'
|
28
|
-
import moment from 'moment-timezone'
|
29
28
|
import { Calendar } from '@instructure/ui-calendar'
|
30
29
|
import { IconButton } from '@instructure/ui-buttons'
|
31
30
|
import {
|
@@ -43,25 +42,12 @@ import { jsx } from '@instructure/emotion'
|
|
43
42
|
import { propTypes } from './props'
|
44
43
|
import type { DateInput2Props } from './props'
|
45
44
|
import type { FormMessage } from '@instructure/ui-form-field'
|
45
|
+
import type { Moment } from '@instructure/ui-i18n'
|
46
46
|
|
47
|
-
function
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
function isValidMomentDate(
|
52
|
-
dateString: string,
|
53
|
-
locale: string,
|
54
|
-
timezone: string
|
55
|
-
): boolean {
|
56
|
-
return moment
|
57
|
-
.tz(
|
58
|
-
dateString,
|
59
|
-
[moment.ISO_8601, 'llll', 'LLLL', 'lll', 'LLL', 'll', 'LL', 'l', 'L'],
|
60
|
-
locale,
|
61
|
-
true,
|
62
|
-
timezone
|
63
|
-
)
|
64
|
-
.isValid()
|
47
|
+
function parseDate(dateString: string): string {
|
48
|
+
const date = new Date(dateString)
|
49
|
+
// return empty string if not a valid date
|
50
|
+
return isNaN(date.getTime()) ? '' : date.toISOString()
|
65
51
|
}
|
66
52
|
|
67
53
|
/**
|
@@ -97,6 +83,8 @@ const DateInput2 = ({
|
|
97
83
|
const localeContext = useContext(ApplyLocaleContext)
|
98
84
|
|
99
85
|
useEffect(() => {
|
86
|
+
// when `value` is changed, validation runs again and removes the error message if validation passes
|
87
|
+
// but it's NOT adding error message if validation fails for better UX
|
100
88
|
validateInput(true)
|
101
89
|
}, [value])
|
102
90
|
|
@@ -106,11 +94,15 @@ const DateInput2 = ({
|
|
106
94
|
|
107
95
|
const handleInputChange = (e: SyntheticEvent, value: string) => {
|
108
96
|
onChange?.(e, value)
|
97
|
+
// blur event formats the input which should trigger parsing
|
98
|
+
if (e.type !== 'blur') {
|
99
|
+
setSelectedDate(parseDate(value))
|
100
|
+
}
|
109
101
|
}
|
110
102
|
|
111
103
|
const handleDateSelected = (
|
112
104
|
dateString: string,
|
113
|
-
_momentDate:
|
105
|
+
_momentDate: Moment,
|
114
106
|
e: SyntheticEvent
|
115
107
|
) => {
|
116
108
|
const formattedDate = new Date(dateString).toLocaleDateString(getLocale(), {
|
@@ -120,30 +112,29 @@ const DateInput2 = ({
|
|
120
112
|
timeZone: getTimezone()
|
121
113
|
})
|
122
114
|
handleInputChange(e, formattedDate)
|
115
|
+
setSelectedDate(dateString)
|
123
116
|
setShowPopover(false)
|
124
|
-
onRequestValidateDate?.(
|
117
|
+
onRequestValidateDate?.(dateString, true)
|
125
118
|
}
|
126
119
|
|
120
|
+
// onlyRemoveError is used to remove the error msg immediately when the user inputs a valid date (and don't wait for blur event)
|
127
121
|
const validateInput = (onlyRemoveError = false): boolean => {
|
128
|
-
//
|
129
|
-
|
130
|
-
// otherwise DateInput could pass invalid dates to Calendar and break it
|
131
|
-
if (
|
132
|
-
(isValidDate(value || '') &&
|
133
|
-
isValidMomentDate(value || '', getLocale(), getTimezone())) ||
|
134
|
-
value === ''
|
135
|
-
) {
|
136
|
-
setSelectedDate(value || '')
|
122
|
+
// don't validate empty input
|
123
|
+
if (!value || parseDate(value) || selectedDate) {
|
137
124
|
setInputMessages(messages || [])
|
138
125
|
return true
|
139
126
|
}
|
140
|
-
if
|
141
|
-
|
127
|
+
// only show error if there is no user provided validation callback
|
128
|
+
if (
|
129
|
+
!onlyRemoveError &&
|
130
|
+
typeof invalidDateErrorMessage === 'string' &&
|
131
|
+
!onRequestValidateDate
|
132
|
+
) {
|
133
|
+
setInputMessages([
|
142
134
|
{
|
143
135
|
type: 'error',
|
144
136
|
text: invalidDateErrorMessage
|
145
|
-
}
|
146
|
-
...messages
|
137
|
+
}
|
147
138
|
])
|
148
139
|
}
|
149
140
|
|
@@ -171,13 +162,16 @@ const DateInput2 = ({
|
|
171
162
|
|
172
163
|
const handleBlur = (e: SyntheticEvent) => {
|
173
164
|
const isInputValid = validateInput(false)
|
174
|
-
if (isInputValid &&
|
175
|
-
const formattedDate = new Date(
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
165
|
+
if (isInputValid && selectedDate) {
|
166
|
+
const formattedDate = new Date(selectedDate).toLocaleDateString(
|
167
|
+
getLocale(),
|
168
|
+
{
|
169
|
+
month: 'long',
|
170
|
+
year: 'numeric',
|
171
|
+
day: 'numeric',
|
172
|
+
timeZone: getTimezone()
|
173
|
+
}
|
174
|
+
)
|
181
175
|
handleInputChange(e, formattedDate)
|
182
176
|
}
|
183
177
|
onRequestValidateDate?.(value, isInputValid)
|
package/src/DateInput2/props.ts
CHANGED
@@ -23,14 +23,14 @@
|
|
23
23
|
*/
|
24
24
|
|
25
25
|
import PropTypes from 'prop-types'
|
26
|
-
import type { SyntheticEvent } from 'react'
|
26
|
+
import type { SyntheticEvent, InputHTMLAttributes } from 'react'
|
27
27
|
|
28
28
|
import { controllable } from '@instructure/ui-prop-types'
|
29
29
|
import { FormPropTypes } from '@instructure/ui-form-field'
|
30
30
|
import type { FormMessage } from '@instructure/ui-form-field'
|
31
|
-
import type { Renderable, PropValidators } from '@instructure/shared-types'
|
31
|
+
import type { OtherHTMLAttributes, Renderable, PropValidators } from '@instructure/shared-types'
|
32
32
|
|
33
|
-
type
|
33
|
+
type DateInput2OwnProps = {
|
34
34
|
/**
|
35
35
|
* Specifies the input label.
|
36
36
|
*/
|
@@ -159,7 +159,13 @@ type DateInput2Props = {
|
|
159
159
|
}
|
160
160
|
}
|
161
161
|
|
162
|
-
type PropKeys = keyof
|
162
|
+
type PropKeys = keyof DateInput2OwnProps
|
163
|
+
|
164
|
+
type DateInput2Props = DateInput2OwnProps &
|
165
|
+
OtherHTMLAttributes<
|
166
|
+
DateInput2OwnProps,
|
167
|
+
InputHTMLAttributes<DateInput2OwnProps & Element>
|
168
|
+
>
|
163
169
|
|
164
170
|
const propTypes: PropValidators<PropKeys> = {
|
165
171
|
renderLabel: PropTypes.oneOfType([PropTypes.node, PropTypes.func]).isRequired,
|
package/src/index.ts
CHANGED