@react-aria/calendar 3.0.0-nightly.3168 → 3.0.0-nightly.3180
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/dist/main.js +45 -15
- package/dist/main.js.map +1 -1
- package/dist/module.js +46 -16
- package/dist/module.js.map +1 -1
- package/dist/types.d.ts +14 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +11 -11
- package/src/useCalendarBase.ts +22 -2
- package/src/useCalendarCell.ts +28 -9
- package/src/useCalendarGrid.ts +2 -2
- package/src/useRangeCalendar.ts +1 -1
- package/src/utils.ts +4 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-aria/calendar",
|
|
3
|
-
"version": "3.0.0-nightly.
|
|
3
|
+
"version": "3.0.0-nightly.3180+0bba35ae3",
|
|
4
4
|
"description": "Spectrum UI components in React",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "dist/main.js",
|
|
@@ -18,15 +18,15 @@
|
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"@babel/runtime": "^7.6.2",
|
|
21
|
-
"@internationalized/date": "3.0.0-nightly.
|
|
22
|
-
"@react-aria/i18n": "3.0.0-nightly.
|
|
23
|
-
"@react-aria/interactions": "3.0.0-nightly.
|
|
24
|
-
"@react-aria/live-announcer": "3.0.0-nightly.
|
|
25
|
-
"@react-aria/utils": "3.0.0-nightly.
|
|
26
|
-
"@react-stately/calendar": "3.0.0-nightly.
|
|
27
|
-
"@react-types/button": "3.4.5-nightly.
|
|
28
|
-
"@react-types/calendar": "3.0.0-nightly.
|
|
29
|
-
"@react-types/shared": "3.0.0-nightly.
|
|
21
|
+
"@internationalized/date": "3.0.0-nightly.3180+0bba35ae3",
|
|
22
|
+
"@react-aria/i18n": "3.0.0-nightly.1481+0bba35ae3",
|
|
23
|
+
"@react-aria/interactions": "3.0.0-nightly.1481+0bba35ae3",
|
|
24
|
+
"@react-aria/live-announcer": "3.0.0-nightly.1481+0bba35ae3",
|
|
25
|
+
"@react-aria/utils": "3.0.0-nightly.1481+0bba35ae3",
|
|
26
|
+
"@react-stately/calendar": "3.0.0-nightly.1481+0bba35ae3",
|
|
27
|
+
"@react-types/button": "3.4.5-nightly.3180+0bba35ae3",
|
|
28
|
+
"@react-types/calendar": "3.0.0-nightly.3180+0bba35ae3",
|
|
29
|
+
"@react-types/shared": "3.0.0-nightly.1481+0bba35ae3",
|
|
30
30
|
"date-fns": "^1.30.1"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
@@ -36,5 +36,5 @@
|
|
|
36
36
|
"publishConfig": {
|
|
37
37
|
"access": "public"
|
|
38
38
|
},
|
|
39
|
-
"gitHead": "
|
|
39
|
+
"gitHead": "0bba35ae36b5d220570385215860d3ca3b549656"
|
|
40
40
|
}
|
package/src/useCalendarBase.ts
CHANGED
|
@@ -20,6 +20,7 @@ import {DOMProps} from '@react-types/shared';
|
|
|
20
20
|
import intlMessages from '../intl/*.json';
|
|
21
21
|
import {mergeProps, useDescription, useId, useUpdateEffect} from '@react-aria/utils';
|
|
22
22
|
import {useMessageFormatter} from '@react-aria/i18n';
|
|
23
|
+
import {useRef} from 'react';
|
|
23
24
|
|
|
24
25
|
export function useCalendarBase(props: CalendarPropsBase & DOMProps, state: CalendarState | RangeCalendarState): CalendarAria {
|
|
25
26
|
let formatMessage = useMessageFormatter(intlMessages);
|
|
@@ -49,6 +50,21 @@ export function useCalendarBase(props: CalendarPropsBase & DOMProps, state: Cale
|
|
|
49
50
|
// Label the child grid elements by the group element if it is labelled.
|
|
50
51
|
calendarIds.set(state, props['aria-label'] || props['aria-labelledby'] ? calendarId : null);
|
|
51
52
|
|
|
53
|
+
// If the next or previous buttons become disabled while they are focused, move focus to the calendar body.
|
|
54
|
+
let nextFocused = useRef(false);
|
|
55
|
+
let nextDisabled = props.isDisabled || state.isNextVisibleRangeInvalid();
|
|
56
|
+
if (nextDisabled && nextFocused.current) {
|
|
57
|
+
nextFocused.current = false;
|
|
58
|
+
state.setFocused(true);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
let previousFocused = useRef(false);
|
|
62
|
+
let previousDisabled = props.isDisabled || state.isPreviousVisibleRangeInvalid();
|
|
63
|
+
if (previousDisabled && previousFocused.current) {
|
|
64
|
+
previousFocused.current = false;
|
|
65
|
+
state.setFocused(true);
|
|
66
|
+
}
|
|
67
|
+
|
|
52
68
|
return {
|
|
53
69
|
calendarProps: mergeProps(descriptionProps, {
|
|
54
70
|
role: 'group',
|
|
@@ -59,12 +75,16 @@ export function useCalendarBase(props: CalendarPropsBase & DOMProps, state: Cale
|
|
|
59
75
|
nextButtonProps: {
|
|
60
76
|
onPress: () => state.focusNextPage(),
|
|
61
77
|
'aria-label': formatMessage('next'),
|
|
62
|
-
isDisabled:
|
|
78
|
+
isDisabled: nextDisabled,
|
|
79
|
+
onFocus: () => nextFocused.current = true,
|
|
80
|
+
onBlur: () => nextFocused.current = false
|
|
63
81
|
},
|
|
64
82
|
prevButtonProps: {
|
|
65
83
|
onPress: () => state.focusPreviousPage(),
|
|
66
84
|
'aria-label': formatMessage('previous'),
|
|
67
|
-
isDisabled:
|
|
85
|
+
isDisabled: previousDisabled,
|
|
86
|
+
onFocus: () => previousFocused.current = true,
|
|
87
|
+
onBlur: () => previousFocused.current = false
|
|
68
88
|
},
|
|
69
89
|
title: visibleRangeDescription
|
|
70
90
|
};
|
package/src/useCalendarCell.ts
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import {CalendarDate, isEqualDay, isSameDay,
|
|
13
|
+
import {CalendarDate, isEqualDay, isSameDay, isToday} from '@internationalized/date';
|
|
14
14
|
import {CalendarState, RangeCalendarState} from '@react-stately/calendar';
|
|
15
15
|
import {focusWithoutScrolling} from '@react-aria/utils';
|
|
16
16
|
import {HTMLAttributes, RefObject, useEffect, useMemo, useRef} from 'react';
|
|
@@ -41,8 +41,21 @@ interface CalendarCellAria {
|
|
|
41
41
|
isSelected: boolean,
|
|
42
42
|
/** Whether the cell is focused. */
|
|
43
43
|
isFocused: boolean,
|
|
44
|
-
/**
|
|
44
|
+
/**
|
|
45
|
+
* Whether the cell is disabled, according to the calendar's `minValue`, `maxValue`, and `isDisabled` props.
|
|
46
|
+
* Disabled dates are not focusable, and cannot be selected by the user. They are typically
|
|
47
|
+
* displayed with a dimmed appearance.
|
|
48
|
+
*/
|
|
45
49
|
isDisabled: boolean,
|
|
50
|
+
/**
|
|
51
|
+
* Whether the cell is unavailable, according to the calendar's `isDateUnavailable` prop. Unavailable dates remain
|
|
52
|
+
* focusable, but cannot be selected by the user. They should be displayed with a visual affordance to indicate they
|
|
53
|
+
* are unavailable, such as a different color or a strikethrough.
|
|
54
|
+
*
|
|
55
|
+
* Note that because they are focusable, unavailable dates must meet a 4.5:1 color contrast ratio,
|
|
56
|
+
* [as defined by WCAG](https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum.html).
|
|
57
|
+
*/
|
|
58
|
+
isUnavailable: boolean,
|
|
46
59
|
/**
|
|
47
60
|
* Whether the cell is outside the visible range of the calendar.
|
|
48
61
|
* For example, dates before the first day of a month in the same week.
|
|
@@ -70,6 +83,8 @@ export function useCalendarCell(props: AriaCalendarCellProps, state: CalendarSta
|
|
|
70
83
|
let isSelected = state.isSelected(date);
|
|
71
84
|
let isFocused = state.isCellFocused(date);
|
|
72
85
|
isDisabled = isDisabled || state.isCellDisabled(date);
|
|
86
|
+
let isUnavailable = state.isCellUnavailable(date);
|
|
87
|
+
let isSelectable = !isDisabled && !isUnavailable;
|
|
73
88
|
|
|
74
89
|
// For performance, reuse the same date object as before if the new date prop is the same.
|
|
75
90
|
// This allows subsequent useMemo results to be reused.
|
|
@@ -102,7 +117,7 @@ export function useCalendarCell(props: AriaCalendarCellProps, state: CalendarSta
|
|
|
102
117
|
|
|
103
118
|
// When a cell is focused and this is a range calendar, add a prompt to help
|
|
104
119
|
// screenreader users know that they are in a range selection mode.
|
|
105
|
-
if ('anchorDate' in state && isFocused && !state.isReadOnly) {
|
|
120
|
+
if ('anchorDate' in state && isFocused && !state.isReadOnly && isSelectable) {
|
|
106
121
|
let rangeSelectionPrompt = '';
|
|
107
122
|
|
|
108
123
|
// If selection has started add "click to finish selecting range"
|
|
@@ -127,7 +142,7 @@ export function useCalendarCell(props: AriaCalendarCellProps, state: CalendarSta
|
|
|
127
142
|
// again to trigger onPressStart. Cancel presses immediately when the pointer exits.
|
|
128
143
|
shouldCancelOnPointerExit: 'anchorDate' in state && !!state.anchorDate,
|
|
129
144
|
preventFocusOnPress: true,
|
|
130
|
-
isDisabled,
|
|
145
|
+
isDisabled: !isSelectable,
|
|
131
146
|
onPressStart(e) {
|
|
132
147
|
if (state.isReadOnly) {
|
|
133
148
|
state.setFocusedDate(date);
|
|
@@ -214,7 +229,10 @@ export function useCalendarCell(props: AriaCalendarCellProps, state: CalendarSta
|
|
|
214
229
|
// there will be an announcement to "click to finish selecting range" (above).
|
|
215
230
|
state.selectDate(date);
|
|
216
231
|
let nextDay = date.add({days: 1});
|
|
217
|
-
if (
|
|
232
|
+
if (state.isInvalid(nextDay)) {
|
|
233
|
+
nextDay = date.subtract({days: 1});
|
|
234
|
+
}
|
|
235
|
+
if (!state.isInvalid(nextDay)) {
|
|
218
236
|
state.setFocusedDate(nextDay);
|
|
219
237
|
}
|
|
220
238
|
} else if (e.pointerType === 'virtual') {
|
|
@@ -249,8 +267,8 @@ export function useCalendarCell(props: AriaCalendarCellProps, state: CalendarSta
|
|
|
249
267
|
return {
|
|
250
268
|
cellProps: {
|
|
251
269
|
role: 'gridcell',
|
|
252
|
-
'aria-disabled':
|
|
253
|
-
'aria-selected': isSelected
|
|
270
|
+
'aria-disabled': !isSelectable || null,
|
|
271
|
+
'aria-selected': isSelectable ? isSelected : null
|
|
254
272
|
},
|
|
255
273
|
buttonProps: mergeProps(pressProps, {
|
|
256
274
|
onFocus() {
|
|
@@ -260,11 +278,11 @@ export function useCalendarCell(props: AriaCalendarCellProps, state: CalendarSta
|
|
|
260
278
|
},
|
|
261
279
|
tabIndex,
|
|
262
280
|
role: 'button',
|
|
263
|
-
'aria-disabled':
|
|
281
|
+
'aria-disabled': !isSelectable || null,
|
|
264
282
|
'aria-label': label,
|
|
265
283
|
onPointerEnter(e) {
|
|
266
284
|
// Highlight the date on hover or drag over a date when selecting a range.
|
|
267
|
-
if ('highlightDate' in state && (e.pointerType !== 'touch' || state.isDragging)) {
|
|
285
|
+
if ('highlightDate' in state && (e.pointerType !== 'touch' || state.isDragging) && isSelectable) {
|
|
268
286
|
state.highlightDate(date);
|
|
269
287
|
}
|
|
270
288
|
},
|
|
@@ -285,6 +303,7 @@ export function useCalendarCell(props: AriaCalendarCellProps, state: CalendarSta
|
|
|
285
303
|
isFocused,
|
|
286
304
|
isSelected,
|
|
287
305
|
isDisabled,
|
|
306
|
+
isUnavailable,
|
|
288
307
|
isOutsideVisibleRange: date.compare(state.visibleRange.start) < 0 || date.compare(state.visibleRange.end) > 0,
|
|
289
308
|
formattedDate
|
|
290
309
|
};
|
package/src/useCalendarGrid.ts
CHANGED
|
@@ -120,8 +120,8 @@ export function useCalendarGrid(props: CalendarGridProps, state: CalendarState |
|
|
|
120
120
|
'aria-labelledby': calendarIds.get(state)
|
|
121
121
|
});
|
|
122
122
|
|
|
123
|
-
let dayFormatter = useDateFormatter({weekday: 'narrow'});
|
|
124
|
-
let dayFormatterLong = useDateFormatter({weekday: 'long'});
|
|
123
|
+
let dayFormatter = useDateFormatter({weekday: 'narrow', timeZone: state.timeZone});
|
|
124
|
+
let dayFormatterLong = useDateFormatter({weekday: 'long', timeZone: state.timeZone});
|
|
125
125
|
let {locale} = useLocale();
|
|
126
126
|
let weekStart = startOfWeek(state.visibleRange.start, locale);
|
|
127
127
|
let weekDays = [...new Array(7).keys()].map((index) => {
|
package/src/useRangeCalendar.ts
CHANGED
|
@@ -53,7 +53,7 @@ export function useRangeCalendar<T extends DateValue>(props: RangeCalendarProps<
|
|
|
53
53
|
let target = e.target as HTMLElement;
|
|
54
54
|
let body = document.getElementById(res.calendarProps.id);
|
|
55
55
|
if (
|
|
56
|
-
(!body.contains(target) || target.
|
|
56
|
+
(!body.contains(target) || !target.closest('[role="button"]')) &&
|
|
57
57
|
!document.getElementById(res.nextButtonProps.id)?.contains(target) &&
|
|
58
58
|
!document.getElementById(res.prevButtonProps.id)?.contains(target)
|
|
59
59
|
) {
|
package/src/utils.ts
CHANGED
|
@@ -50,12 +50,14 @@ export function useVisibleRangeDescription(startDate: CalendarDate, endDate: Cal
|
|
|
50
50
|
month: 'long',
|
|
51
51
|
year: 'numeric',
|
|
52
52
|
era: startDate.calendar.identifier !== 'gregory' ? 'long' : undefined,
|
|
53
|
-
calendar: startDate.calendar.identifier
|
|
53
|
+
calendar: startDate.calendar.identifier,
|
|
54
|
+
timeZone
|
|
54
55
|
});
|
|
55
56
|
|
|
56
57
|
let dateFormatter = useDateFormatter({
|
|
57
58
|
dateStyle: 'long',
|
|
58
|
-
calendar: startDate.calendar.identifier
|
|
59
|
+
calendar: startDate.calendar.identifier,
|
|
60
|
+
timeZone
|
|
59
61
|
});
|
|
60
62
|
|
|
61
63
|
return useMemo(() => {
|