@instructure/ui-date-input 11.6.0 → 11.6.1-snapshot-129

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.
Files changed (63) hide show
  1. package/CHANGELOG.md +48 -309
  2. package/es/DateInput/{index.js → v1/index.js} +4 -4
  3. package/es/DateInput/v2/index.js +407 -0
  4. package/es/DateInput/v2/props.js +26 -0
  5. package/es/DateInput/v2/styles.js +46 -0
  6. package/es/DateInput2/{index.js → v1/index.js} +13 -11
  7. package/es/{index.js → exports/a.js} +2 -2
  8. package/{src/index.ts → es/exports/b.js} +2 -5
  9. package/lib/DateInput/{index.js → v1/index.js} +9 -9
  10. package/lib/DateInput/v2/index.js +416 -0
  11. package/lib/DateInput/v2/props.js +31 -0
  12. package/lib/DateInput/v2/styles.js +52 -0
  13. package/lib/DateInput2/{index.js → v1/index.js} +19 -19
  14. package/lib/{index.js → exports/a.js} +4 -4
  15. package/lib/exports/b.js +19 -0
  16. package/package.json +45 -23
  17. package/src/DateInput/{index.tsx → v1/index.tsx} +10 -7
  18. package/src/DateInput/{props.ts → v1/props.ts} +2 -2
  19. package/src/DateInput/v2/README.md +315 -0
  20. package/src/DateInput/v2/index.tsx +498 -0
  21. package/src/DateInput/v2/props.ts +316 -0
  22. package/src/DateInput/v2/styles.ts +52 -0
  23. package/src/DateInput2/{README.md → v1/README.md} +9 -9
  24. package/src/DateInput2/{index.tsx → v1/index.tsx} +11 -11
  25. package/src/DateInput2/{props.ts → v1/props.ts} +1 -1
  26. package/src/exports/a.ts +28 -0
  27. package/src/exports/b.ts +28 -0
  28. package/tsconfig.build.tsbuildinfo +1 -1
  29. package/types/DateInput/{index.d.ts → v1/index.d.ts} +4 -4
  30. package/types/DateInput/v1/index.d.ts.map +1 -0
  31. package/types/DateInput/{props.d.ts → v1/props.d.ts} +2 -2
  32. package/types/DateInput/v1/props.d.ts.map +1 -0
  33. package/types/DateInput/v1/styles.d.ts.map +1 -0
  34. package/types/DateInput/v2/index.d.ts +109 -0
  35. package/types/DateInput/v2/index.d.ts.map +1 -0
  36. package/types/DateInput/v2/props.d.ts +234 -0
  37. package/types/DateInput/v2/props.d.ts.map +1 -0
  38. package/types/DateInput/v2/styles.d.ts +13 -0
  39. package/types/DateInput/v2/styles.d.ts.map +1 -0
  40. package/types/DateInput2/{index.d.ts → v1/index.d.ts} +2 -2
  41. package/types/DateInput2/v1/index.d.ts.map +1 -0
  42. package/types/DateInput2/{props.d.ts → v1/props.d.ts} +1 -1
  43. package/types/DateInput2/v1/props.d.ts.map +1 -0
  44. package/types/exports/a.d.ts +5 -0
  45. package/types/exports/a.d.ts.map +1 -0
  46. package/types/exports/b.d.ts +5 -0
  47. package/types/exports/b.d.ts.map +1 -0
  48. package/types/DateInput/index.d.ts.map +0 -1
  49. package/types/DateInput/props.d.ts.map +0 -1
  50. package/types/DateInput/styles.d.ts.map +0 -1
  51. package/types/DateInput2/index.d.ts.map +0 -1
  52. package/types/DateInput2/props.d.ts.map +0 -1
  53. package/types/index.d.ts +0 -5
  54. package/types/index.d.ts.map +0 -1
  55. /package/es/DateInput/{props.js → v1/props.js} +0 -0
  56. /package/es/DateInput/{styles.js → v1/styles.js} +0 -0
  57. /package/es/DateInput2/{props.js → v1/props.js} +0 -0
  58. /package/lib/DateInput/{props.js → v1/props.js} +0 -0
  59. /package/lib/DateInput/{styles.js → v1/styles.js} +0 -0
  60. /package/lib/DateInput2/{props.js → v1/props.js} +0 -0
  61. /package/src/DateInput/{README.md → v1/README.md} +0 -0
  62. /package/src/DateInput/{styles.ts → v1/styles.ts} +0 -0
  63. /package/types/DateInput/{styles.d.ts → v1/styles.d.ts} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@instructure/ui-date-input",
3
- "version": "11.6.0",
3
+ "version": "11.6.1-snapshot-129",
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",
@@ -16,27 +16,27 @@
16
16
  "dependencies": {
17
17
  "@babel/runtime": "^7.27.6",
18
18
  "moment-timezone": "^0.6.0",
19
- "@instructure/emotion": "11.6.0",
20
- "@instructure/shared-types": "11.6.0",
21
- "@instructure/ui-calendar": "11.6.0",
22
- "@instructure/ui-i18n": "11.6.0",
23
- "@instructure/ui-form-field": "11.6.0",
24
- "@instructure/ui-icons": "11.6.0",
25
- "@instructure/ui-popover": "11.6.0",
26
- "@instructure/ui-selectable": "11.6.0",
27
- "@instructure/ui-text-input": "11.6.0",
28
- "@instructure/ui-utils": "11.6.0",
29
- "@instructure/ui-react-utils": "11.6.0",
30
- "@instructure/ui-position": "11.6.0"
19
+ "@instructure/emotion": "11.6.1-snapshot-129",
20
+ "@instructure/ui-calendar": "11.6.1-snapshot-129",
21
+ "@instructure/shared-types": "11.6.1-snapshot-129",
22
+ "@instructure/ui-i18n": "11.6.1-snapshot-129",
23
+ "@instructure/ui-form-field": "11.6.1-snapshot-129",
24
+ "@instructure/ui-icons": "11.6.1-snapshot-129",
25
+ "@instructure/ui-react-utils": "11.6.1-snapshot-129",
26
+ "@instructure/ui-popover": "11.6.1-snapshot-129",
27
+ "@instructure/ui-selectable": "11.6.1-snapshot-129",
28
+ "@instructure/ui-position": "11.6.1-snapshot-129",
29
+ "@instructure/ui-text-input": "11.6.1-snapshot-129",
30
+ "@instructure/ui-utils": "11.6.1-snapshot-129"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@testing-library/jest-dom": "^6.6.3",
34
34
  "@testing-library/react": "15.0.7",
35
35
  "@testing-library/user-event": "^14.6.1",
36
36
  "vitest": "^3.2.2",
37
- "@instructure/ui-babel-preset": "11.6.0",
38
- "@instructure/ui-buttons": "11.6.0",
39
- "@instructure/ui-scripts": "11.6.0"
37
+ "@instructure/ui-scripts": "11.6.1-snapshot-129",
38
+ "@instructure/ui-babel-preset": "11.6.1-snapshot-129",
39
+ "@instructure/ui-buttons": "11.6.1-snapshot-129"
40
40
  },
41
41
  "peerDependencies": {
42
42
  "react": ">=18 <=19"
@@ -46,17 +46,39 @@
46
46
  },
47
47
  "sideEffects": false,
48
48
  "exports": {
49
- ".": {
50
- "types": "./types/index.d.ts",
51
- "import": "./es/index.js",
52
- "require": "./lib/index.js",
53
- "default": "./es/index.js"
54
- },
55
49
  "./lib/*": "./lib/*",
56
50
  "./es/*": "./es/*",
57
51
  "./types/*": "./types/*",
58
52
  "./package.json": "./package.json",
59
- "./src/*": "./src/*"
53
+ "./src/*": "./src/*",
54
+ ".": {
55
+ "src": "./src/exports/a.ts",
56
+ "types": "./types/exports/a.d.ts",
57
+ "import": "./es/exports/a.js",
58
+ "require": "./lib/exports/a.js",
59
+ "default": "./es/exports/a.js"
60
+ },
61
+ "./v11_6": {
62
+ "src": "./src/exports/a.ts",
63
+ "types": "./types/exports/a.d.ts",
64
+ "import": "./es/exports/a.js",
65
+ "require": "./lib/exports/a.js",
66
+ "default": "./es/exports/a.js"
67
+ },
68
+ "./v11_7": {
69
+ "src": "./src/exports/b.ts",
70
+ "types": "./types/exports/b.d.ts",
71
+ "import": "./es/exports/b.js",
72
+ "require": "./lib/exports/b.js",
73
+ "default": "./es/exports/b.js"
74
+ },
75
+ "./latest": {
76
+ "src": "./src/exports/b.ts",
77
+ "types": "./types/exports/b.d.ts",
78
+ "import": "./es/exports/b.js",
79
+ "require": "./lib/exports/b.js",
80
+ "default": "./es/exports/b.js"
81
+ }
60
82
  },
61
83
  "scripts": {
62
84
  "lint": "ui-scripts lint",
@@ -24,17 +24,20 @@
24
24
 
25
25
  import { Children, Component, ReactElement } from 'react'
26
26
 
27
- import { Calendar } from '@instructure/ui-calendar'
28
- import type { CalendarProps, CalendarDayProps } from '@instructure/ui-calendar'
27
+ import { Calendar } from '@instructure/ui-calendar/v11_6'
28
+ import type {
29
+ CalendarProps,
30
+ CalendarDayProps
31
+ } from '@instructure/ui-calendar/v11_6'
29
32
  import { IconCalendarMonthLine } from '@instructure/ui-icons'
30
- import { Popover } from '@instructure/ui-popover'
33
+ import { Popover } from '@instructure/ui-popover/v11_6'
31
34
  import { Selectable } from '@instructure/ui-selectable'
32
35
  import type {
33
36
  SelectableProps,
34
37
  SelectableRender
35
38
  } from '@instructure/ui-selectable'
36
- import { TextInput } from '@instructure/ui-text-input'
37
- import type { TextInputProps } from '@instructure/ui-text-input'
39
+ import { TextInput } from '@instructure/ui-text-input/v11_6'
40
+ import type { TextInputProps } from '@instructure/ui-text-input/v11_6'
38
41
  import { createChainedFunction } from '@instructure/ui-utils'
39
42
  import {
40
43
  getInteraction,
@@ -45,13 +48,13 @@ import {
45
48
 
46
49
  import { DateTime, ApplyLocaleContext, Locale } from '@instructure/ui-i18n'
47
50
 
48
- import { withStyle } from '@instructure/emotion'
51
+ import { withStyleLegacy as withStyle } from '@instructure/emotion'
49
52
 
50
53
  import generateStyle from './styles'
51
54
 
52
55
  import { allowedProps } from './props'
53
56
  import type { DateInputProps, DateInputState } from './props'
54
- import type { FormMessage } from '@instructure/ui-form-field'
57
+ import type { FormMessage } from '@instructure/ui-form-field/v11_6'
55
58
 
56
59
  /**
57
60
  ---
@@ -22,8 +22,8 @@
22
22
  * SOFTWARE.
23
23
  */
24
24
 
25
- import type { CalendarDayProps } from '@instructure/ui-calendar'
26
- import type { FormMessage } from '@instructure/ui-form-field'
25
+ import type { CalendarDayProps } from '@instructure/ui-calendar/v11_6'
26
+ import type { FormMessage } from '@instructure/ui-form-field/v11_6'
27
27
  import type { PlacementPropValues } from '@instructure/ui-position'
28
28
  import type { Renderable, OtherHTMLAttributes } from '@instructure/shared-types'
29
29
  import type { WithStyleProps, ComponentStyle } from '@instructure/emotion'
@@ -0,0 +1,315 @@
1
+ ---
2
+ describes: DateInput
3
+ ---
4
+
5
+ > _Note:_ we recommend to update to the new [`DateInput2`](/#DateInput2) which is easier to configure for developers, has a better UX, better accessibility features and a year picker. `DateInput` will be deprecated in the future.
6
+
7
+ The `DateInput` component provides a visual interface for inputting date data.
8
+
9
+ ### Composing a DateInput in your Application
10
+
11
+ `DateInput` uses `Calendar` internally. See [Calendar](Calendar) for more detailed
12
+ documentation and guided examples. `DateInput` shares many of the same `Calendar`
13
+ props and it is created the same way with some additional attributes and callback
14
+ methods for the input. The following example is configured similar to the `Calendar`
15
+ examples using [Moment.js](https://momentjs.com/docs/#/parsing/).
16
+
17
+ ```javascript
18
+ ---
19
+ type: example
20
+ ---
21
+
22
+ class Example extends React.Component {
23
+ state = {
24
+ value: '',
25
+ isShowingCalendar: false,
26
+ todayDate: parseDate('2019-08-28').toISOString(),
27
+ selectedDate: null,
28
+ renderedDate: parseDate('2019-08-01').toISOString(),
29
+ disabledDates: [
30
+ parseDate('2019-08-14').toISOString(),
31
+ parseDate('2019-08-19').toISOString(),
32
+ parseDate('2019-08-29').toISOString()
33
+ ],
34
+ messages: []
35
+ }
36
+
37
+ generateMonth = (renderedDate = this.state.renderedDate) => {
38
+ const date = parseDate(renderedDate)
39
+ .startOf('month')
40
+ .startOf('week')
41
+
42
+ return Array.apply(null, Array(Calendar.DAY_COUNT)).map(() => {
43
+ const currentDate = date.clone()
44
+ date.add({days: 1})
45
+
46
+ // This workaround is needed because moment's `.add({days: 1})` function has a bug that happens when the date added lands perfectly onto the DST cutoff,
47
+ // in these cases adding 1 day results in 23 hours added instead,
48
+ // so `moment.tz('2024-09-07T00:00:00', 'America/Santiago').add({days: 1})` results
49
+ // in "Sat Sep 07 2024 23:00:00 GMT-0400" instead of "Sun Sep 08 2024 00:00:00 GMT-0400".
50
+ // which would cause duplicate dates in the calendar.
51
+ // More info on the bug: https://github.com/moment/moment/issues/4743
52
+ // Please note that this causes one hour of time difference in the affected timezones/dates and to
53
+ // fully solve this bug we need to change to something like luxon which handles this properly
54
+ if (currentDate.clone().format('HH') === '23') {
55
+ return currentDate.clone().add({hours: 1})
56
+ }
57
+
58
+ return currentDate.clone()
59
+ })
60
+ }
61
+
62
+ formatDate = (dateInput) => {
63
+ const date = parseDate(dateInput)
64
+ return `${date.format('MMMM')} ${date.format('D')}, ${date.format('YYYY')}`
65
+ }
66
+
67
+ handleChange = (event, { value }) => {
68
+ const newDateStr = parseDate(value).toISOString()
69
+
70
+ this.setState(({ renderedDate }) => ({
71
+ value,
72
+ selectedDate: newDateStr,
73
+ renderedDate: newDateStr || renderedDate,
74
+ messages: []
75
+ }))
76
+ }
77
+
78
+ handleShowCalendar = (event) => {
79
+ this.setState({ isShowingCalendar: true })
80
+ }
81
+
82
+ handleHideCalendar = (event) => {
83
+ this.setState(({ selectedDate, disabledDates, value }) => ({
84
+ isShowingCalendar: false,
85
+ value: selectedDate ? this.formatDate(selectedDate) : value
86
+ }))
87
+ }
88
+
89
+ handleValidateDate = (event) => {
90
+ this.setState(({ selectedDate, value }) => {
91
+ // We don't have a selectedDate but we have a value. That means that the value
92
+ // could not be parsed and so the date is invalid
93
+ if (!selectedDate && value) {
94
+ return {
95
+ messages: [{ type: 'error', text: 'This date is invalid' }],
96
+ }
97
+ }
98
+ // Display a message if the user has typed in a value that corresponds to a
99
+ // disabledDate
100
+ if (this.isDisabledDate(parseDate(selectedDate))) {
101
+ return {
102
+ messages: [{ type: 'error', text: 'This date is disabled' }],
103
+ }
104
+ }
105
+ })
106
+ }
107
+
108
+ handleDayClick = (event, { date }) => {
109
+ this.setState({
110
+ selectedDate: date,
111
+ renderedDate: date,
112
+ messages: []
113
+ })
114
+ }
115
+
116
+ handleSelectNextDay = (event) => {
117
+ this.modifySelectedDate('day', 1)
118
+ }
119
+
120
+ handleSelectPrevDay = (event) => {
121
+ this.modifySelectedDate('day', -1)
122
+ }
123
+
124
+ handleRenderNextMonth = (event) => {
125
+ this.modifyRenderedDate('month', 1)
126
+ }
127
+
128
+ handleRenderPrevMonth = (event) => {
129
+ this.modifyRenderedDate('month', -1)
130
+ }
131
+
132
+ modifyRenderedDate = (type, step) => {
133
+ this.setState(({ renderedDate }) => {
134
+ return { renderedDate: this.modifyDate(renderedDate, type, step) }
135
+ })
136
+ }
137
+
138
+ modifySelectedDate = (type, step) => {
139
+ this.setState(({ selectedDate, renderedDate }) => {
140
+ // We are either going to increase or decrease our selectedDate by 1 day.
141
+ // If we do not have a selectedDate yet, we'll just select the first day of
142
+ // the currently rendered month instead.
143
+ const newDate = selectedDate
144
+ ? this.modifyDate(selectedDate, type, step)
145
+ : parseDate(renderedDate).startOf('month').toISOString()
146
+
147
+ return {
148
+ selectedDate: newDate,
149
+ renderedDate: newDate,
150
+ value: this.formatDate(newDate),
151
+ messages: []
152
+ }
153
+ })
154
+ }
155
+
156
+ modifyDate = (dateStr, type, step) => {
157
+ const date = parseDate(dateStr)
158
+ date.add(step, type)
159
+ return date.toISOString()
160
+ }
161
+
162
+ isDisabledDate = (date, disabledDates = this.state.disabledDates) => {
163
+ return disabledDates.reduce((result, disabledDate) => {
164
+ return result || date.isSame(disabledDate, 'day')
165
+ }, false)
166
+ }
167
+
168
+ renderWeekdayLabels = () => {
169
+ const date = parseDate(this.state.renderedDate).startOf('week')
170
+
171
+ return Array.apply(null, Array(7)).map(() => {
172
+ const currentDate = date.clone()
173
+ date.add(1, 'day')
174
+
175
+ return (
176
+ <AccessibleContent alt={currentDate.format('dddd')}>
177
+ {currentDate.format('dd')}
178
+ </AccessibleContent>
179
+ )
180
+ })
181
+ }
182
+
183
+ renderDays () {
184
+ const {
185
+ renderedDate,
186
+ selectedDate,
187
+ todayDate,
188
+ } = this.state
189
+
190
+ return this.generateMonth().map((date) => {
191
+ const dateStr = date.toISOString()
192
+
193
+ return (
194
+ <DateInput.Day
195
+ key={dateStr}
196
+ date={dateStr}
197
+ interaction={this.isDisabledDate(date) ? 'disabled' : 'enabled'}
198
+ isSelected={date.isSame(selectedDate, 'day')}
199
+ isToday={date.isSame(todayDate, 'day')}
200
+ isOutsideMonth={!date.isSame(renderedDate, 'month')}
201
+ label={`${date.format('D')} ${date.format('MMMM')} ${date.format('YYYY')}`}
202
+ onClick={this.handleDayClick}
203
+ >
204
+ {date.format('D')}
205
+ </DateInput.Day>
206
+ )
207
+ })
208
+ }
209
+
210
+ render () {
211
+ const {
212
+ value,
213
+ isShowingCalendar,
214
+ renderedDate,
215
+ messages
216
+ } = this.state
217
+
218
+ const date = parseDate(this.state.renderedDate)
219
+
220
+ const buttonProps = (type = 'prev') => ({
221
+ size: 'small',
222
+ withBackground: false,
223
+ withBorder: false,
224
+ renderIcon: type === 'prev'
225
+ ? <ChevronLeftInstUIIcon color="baseColor" />
226
+ : <ChevronRightInstUIIcon color="baseColor" />,
227
+ screenReaderLabel: type === 'prev' ? 'Previous month' : 'Next month'
228
+ })
229
+
230
+ return (
231
+ <DateInput
232
+ renderLabel="Choose a date"
233
+ assistiveText="Type a date or use arrow keys to navigate date picker."
234
+ value={value}
235
+ onChange={this.handleChange}
236
+ width="20rem"
237
+ isInline
238
+ messages={messages}
239
+ isShowingCalendar = {this.state.isShowingCalendar}
240
+ onRequestValidateDate={this.handleValidateDate}
241
+ onRequestShowCalendar={this.handleShowCalendar}
242
+ onRequestHideCalendar={this.handleHideCalendar}
243
+ onRequestSelectNextDay={this.handleSelectNextDay}
244
+ onRequestSelectPrevDay={this.handleSelectPrevDay}
245
+ onRequestRenderNextMonth={this.handleRenderNextMonth}
246
+ onRequestRenderPrevMonth={this.handleRenderPrevMonth}
247
+ renderNavigationLabel={
248
+ <span>
249
+ <div>{date.format('MMMM')}</div>
250
+ <div>{date.format('YYYY')}</div>
251
+ </span>
252
+ }
253
+ renderPrevMonthButton={<IconButton {...buttonProps('prev')} />}
254
+ renderNextMonthButton={<IconButton {...buttonProps('next')} />}
255
+ renderWeekdayLabels={this.renderWeekdayLabels()}
256
+ >
257
+ {this.renderDays()}
258
+ </DateInput>
259
+ )
260
+ }
261
+ }
262
+
263
+ const locale = 'en-us'
264
+ const timezone = 'America/Denver'
265
+
266
+ const parseDate = (dateStr) => {
267
+ return moment.tz(dateStr, [moment.ISO_8601, 'llll', 'LLLL', 'lll', 'LLL', 'll', 'LL', 'l', 'L'], locale, timezone)
268
+ }
269
+
270
+ render(<Example />)
271
+ ```
272
+
273
+ #### Some dates to keep track of
274
+
275
+ - `todayDate` - the date that represents today
276
+ - `selectedDate` - the user's selected date
277
+ - `renderedDate` - the date that the user is viewing as they navigate the `Calendar`
278
+ - `disabledDates` - any dates that are disabled
279
+
280
+ #### Rendering `DateInput.Day` children
281
+
282
+ `DateInput` accepts children of type `DateInput.Day`. Both `DateInput.Day` and
283
+ `Calendar.Day` are exporting the same `Day` component. The documentation for
284
+ `Day` can be found in [Calendar](Calendar).
285
+
286
+ #### Handling onChange
287
+
288
+ When the `DateInput` fires an `onChange` event:
289
+
290
+ - The value should be updated and any messages should be cleared
291
+ - Verify if the value can be parsed as a date
292
+ - If it can be parsed, update the `selectedDate` and `renderedDate` with that date
293
+ - If it cannot be parsed, the `selectedDate` is set to null and the `renderedDate`
294
+ stays the same
295
+
296
+ #### Handling onRequestHideCalendar
297
+
298
+ When the `DateInput` fires `onRequestHideCalendar`:
299
+
300
+ - The calendar should be hidden
301
+ - The value should be updated with a formatted version of the `selectedDate` if
302
+ it exists. See "Formatting user input" below
303
+
304
+ #### Formatting user input
305
+
306
+ Date formats can vary widely (ex. '8-9-19' vs '8/9/19'). When the `Calendar` is
307
+ hidden, the input value should be converted to a consistent, standardized format.
308
+ The formatted result of the raw input '8/9/19'
309
+ could be "August 9, 2019".
310
+
311
+ #### Handling onRequestValidateDate
312
+
313
+ When the `DateInput` fires `onRequestValidateDate`, the provided user input
314
+ should be validated. If the value cannot be parsed as a valid date, or if the
315
+ `selectedDate` is disabled, the user should be notified via the `messages` prop.