@react-aria/calendar 3.0.0-rc.0 → 3.0.1
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 +698 -66
- package/dist/main.js.map +1 -1
- package/dist/module.js +700 -68
- package/dist/module.js.map +1 -1
- package/dist/types.d.ts +9 -8
- package/dist/types.d.ts.map +1 -1
- package/package.json +13 -13
- package/src/useCalendarBase.ts +8 -7
- package/src/useCalendarCell.ts +22 -19
- package/src/useCalendarGrid.ts +15 -6
- package/src/useRangeCalendar.ts +4 -3
- package/src/utils.ts +28 -15
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-aria/calendar",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.1",
|
|
4
4
|
"description": "Spectrum UI components in React",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "dist/main.js",
|
|
@@ -18,22 +18,22 @@
|
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"@babel/runtime": "^7.6.2",
|
|
21
|
-
"@internationalized/date": "3.0.
|
|
22
|
-
"@react-aria/i18n": "^3.
|
|
23
|
-
"@react-aria/interactions": "^3.
|
|
24
|
-
"@react-aria/live-announcer": "^3.
|
|
25
|
-
"@react-aria/utils": "^3.
|
|
26
|
-
"@react-stately/calendar": "3.0.
|
|
27
|
-
"@react-types/button": "^3.
|
|
28
|
-
"@react-types/calendar": "3.0.
|
|
29
|
-
"@react-types/shared": "^3.
|
|
21
|
+
"@internationalized/date": "^3.0.1",
|
|
22
|
+
"@react-aria/i18n": "^3.5.0",
|
|
23
|
+
"@react-aria/interactions": "^3.10.0",
|
|
24
|
+
"@react-aria/live-announcer": "^3.1.1",
|
|
25
|
+
"@react-aria/utils": "^3.13.2",
|
|
26
|
+
"@react-stately/calendar": "^3.0.1",
|
|
27
|
+
"@react-types/button": "^3.6.0",
|
|
28
|
+
"@react-types/calendar": "^3.0.1",
|
|
29
|
+
"@react-types/shared": "^3.14.0"
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
|
-
"react": "^16.8.0 || ^17.0.0-rc.1",
|
|
33
|
-
"react-dom": "^16.8.0 || ^17.0.0-rc.1"
|
|
32
|
+
"react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0",
|
|
33
|
+
"react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
|
|
34
34
|
},
|
|
35
35
|
"publishConfig": {
|
|
36
36
|
"access": "public"
|
|
37
37
|
},
|
|
38
|
-
"gitHead": "
|
|
38
|
+
"gitHead": "cd7c0ec917122c7612f653c22f8ed558f8b66ecd"
|
|
39
39
|
}
|
package/src/useCalendarBase.ts
CHANGED
|
@@ -14,29 +14,30 @@ import {announce} from '@react-aria/live-announcer';
|
|
|
14
14
|
import {AriaButtonProps} from '@react-types/button';
|
|
15
15
|
import {CalendarPropsBase} from '@react-types/calendar';
|
|
16
16
|
import {CalendarState, RangeCalendarState} from '@react-stately/calendar';
|
|
17
|
+
import {DOMAttributes} from '@react-types/shared';
|
|
17
18
|
import {DOMProps} from '@react-types/shared';
|
|
18
19
|
import {filterDOMProps, mergeProps, useLabels, useSlotId, useUpdateEffect} from '@react-aria/utils';
|
|
19
20
|
import {hookData, useSelectedDateDescription, useVisibleRangeDescription} from './utils';
|
|
20
|
-
import {HTMLAttributes, useRef} from 'react';
|
|
21
21
|
// @ts-ignore
|
|
22
22
|
import intlMessages from '../intl/*.json';
|
|
23
|
-
import {
|
|
23
|
+
import {useLocalizedStringFormatter} from '@react-aria/i18n';
|
|
24
|
+
import {useRef} from 'react';
|
|
24
25
|
|
|
25
26
|
export interface CalendarAria {
|
|
26
27
|
/** Props for the calendar grouping element. */
|
|
27
|
-
calendarProps:
|
|
28
|
+
calendarProps: DOMAttributes,
|
|
28
29
|
/** Props for the next button. */
|
|
29
30
|
nextButtonProps: AriaButtonProps,
|
|
30
31
|
/** Props for the previous button. */
|
|
31
32
|
prevButtonProps: AriaButtonProps,
|
|
32
33
|
/** Props for the error message element, if any. */
|
|
33
|
-
errorMessageProps:
|
|
34
|
+
errorMessageProps: DOMAttributes,
|
|
34
35
|
/** A description of the visible date range, for use in the calendar title. */
|
|
35
36
|
title: string
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
export function useCalendarBase(props: CalendarPropsBase & DOMProps, state: CalendarState | RangeCalendarState): CalendarAria {
|
|
39
|
-
let
|
|
40
|
+
let stringFormatter = useLocalizedStringFormatter(intlMessages);
|
|
40
41
|
let domProps = filterDOMProps(props);
|
|
41
42
|
|
|
42
43
|
let title = useVisibleRangeDescription(state.visibleRange.start, state.visibleRange.end, state.timeZone, false);
|
|
@@ -97,14 +98,14 @@ export function useCalendarBase(props: CalendarPropsBase & DOMProps, state: Cale
|
|
|
97
98
|
}),
|
|
98
99
|
nextButtonProps: {
|
|
99
100
|
onPress: () => state.focusNextPage(),
|
|
100
|
-
'aria-label':
|
|
101
|
+
'aria-label': stringFormatter.format('next'),
|
|
101
102
|
isDisabled: nextDisabled,
|
|
102
103
|
onFocus: () => nextFocused.current = true,
|
|
103
104
|
onBlur: () => nextFocused.current = false
|
|
104
105
|
},
|
|
105
106
|
prevButtonProps: {
|
|
106
107
|
onPress: () => state.focusPreviousPage(),
|
|
107
|
-
'aria-label':
|
|
108
|
+
'aria-label': stringFormatter.format('previous'),
|
|
108
109
|
isDisabled: previousDisabled,
|
|
109
110
|
onFocus: () => previousFocused.current = true,
|
|
110
111
|
onBlur: () => previousFocused.current = false
|
package/src/useCalendarCell.ts
CHANGED
|
@@ -12,14 +12,15 @@
|
|
|
12
12
|
|
|
13
13
|
import {CalendarDate, isEqualDay, isSameDay, isToday} from '@internationalized/date';
|
|
14
14
|
import {CalendarState, RangeCalendarState} from '@react-stately/calendar';
|
|
15
|
-
import {
|
|
15
|
+
import {DOMAttributes} from '@react-types/shared';
|
|
16
|
+
import {focusWithoutScrolling, getScrollParent, scrollIntoView, useDescription} from '@react-aria/utils';
|
|
17
|
+
import {getEraFormat, hookData} from './utils';
|
|
16
18
|
import {getInteractionModality, usePress} from '@react-aria/interactions';
|
|
17
|
-
import {hookData} from './utils';
|
|
18
|
-
import {HTMLAttributes, RefObject, useEffect, useMemo, useRef} from 'react';
|
|
19
19
|
// @ts-ignore
|
|
20
20
|
import intlMessages from '../intl/*.json';
|
|
21
21
|
import {mergeProps} from '@react-aria/utils';
|
|
22
|
-
import {
|
|
22
|
+
import {RefObject, useEffect, useMemo, useRef} from 'react';
|
|
23
|
+
import {useDateFormatter, useLocalizedStringFormatter} from '@react-aria/i18n';
|
|
23
24
|
|
|
24
25
|
export interface AriaCalendarCellProps {
|
|
25
26
|
/** The date that this cell represents. */
|
|
@@ -33,9 +34,9 @@ export interface AriaCalendarCellProps {
|
|
|
33
34
|
|
|
34
35
|
export interface CalendarCellAria {
|
|
35
36
|
/** Props for the grid cell element (e.g. `<td>`). */
|
|
36
|
-
cellProps:
|
|
37
|
+
cellProps: DOMAttributes,
|
|
37
38
|
/** Props for the button element within the cell. */
|
|
38
|
-
buttonProps:
|
|
39
|
+
buttonProps: DOMAttributes,
|
|
39
40
|
/** Whether the cell is currently being pressed. */
|
|
40
41
|
isPressed: boolean,
|
|
41
42
|
/** Whether the cell is selected. */
|
|
@@ -75,13 +76,13 @@ export interface CalendarCellAria {
|
|
|
75
76
|
export function useCalendarCell(props: AriaCalendarCellProps, state: CalendarState | RangeCalendarState, ref: RefObject<HTMLElement>): CalendarCellAria {
|
|
76
77
|
let {date, isDisabled} = props;
|
|
77
78
|
let {errorMessageId, selectedDateDescription} = hookData.get(state);
|
|
78
|
-
let
|
|
79
|
+
let stringFormatter = useLocalizedStringFormatter(intlMessages);
|
|
79
80
|
let dateFormatter = useDateFormatter({
|
|
80
81
|
weekday: 'long',
|
|
81
82
|
day: 'numeric',
|
|
82
83
|
month: 'long',
|
|
83
84
|
year: 'numeric',
|
|
84
|
-
era: date
|
|
85
|
+
era: getEraFormat(date),
|
|
85
86
|
timeZone: state.timeZone
|
|
86
87
|
});
|
|
87
88
|
let isSelected = state.isSelected(date);
|
|
@@ -129,24 +130,24 @@ export function useCalendarCell(props: AriaCalendarCellProps, state: CalendarSta
|
|
|
129
130
|
label += dateFormatter.format(nativeDate);
|
|
130
131
|
if (isDateToday) {
|
|
131
132
|
// If date is today, set appropriate string depending on selected state:
|
|
132
|
-
label =
|
|
133
|
+
label = stringFormatter.format(isSelected ? 'todayDateSelected' : 'todayDate', {
|
|
133
134
|
date: label
|
|
134
135
|
});
|
|
135
136
|
} else if (isSelected) {
|
|
136
137
|
// If date is selected but not today:
|
|
137
|
-
label =
|
|
138
|
+
label = stringFormatter.format('dateSelected', {
|
|
138
139
|
date: label
|
|
139
140
|
});
|
|
140
141
|
}
|
|
141
142
|
|
|
142
143
|
if (state.minValue && isSameDay(date, state.minValue)) {
|
|
143
|
-
label += ', ' +
|
|
144
|
+
label += ', ' + stringFormatter.format('minimumDate');
|
|
144
145
|
} else if (state.maxValue && isSameDay(date, state.maxValue)) {
|
|
145
|
-
label += ', ' +
|
|
146
|
+
label += ', ' + stringFormatter.format('maximumDate');
|
|
146
147
|
}
|
|
147
148
|
|
|
148
149
|
return label;
|
|
149
|
-
}, [dateFormatter, nativeDate,
|
|
150
|
+
}, [dateFormatter, nativeDate, stringFormatter, isSelected, isDateToday, date, state, selectedDateDescription]);
|
|
150
151
|
|
|
151
152
|
// When a cell is focused and this is a range calendar, add a prompt to help
|
|
152
153
|
// screenreader users know that they are in a range selection mode.
|
|
@@ -154,10 +155,10 @@ export function useCalendarCell(props: AriaCalendarCellProps, state: CalendarSta
|
|
|
154
155
|
if ('anchorDate' in state && isFocused && !state.isReadOnly && isSelectable) {
|
|
155
156
|
// If selection has started add "click to finish selecting range"
|
|
156
157
|
if (state.anchorDate) {
|
|
157
|
-
rangeSelectionPrompt =
|
|
158
|
+
rangeSelectionPrompt = stringFormatter.format('finishRangeSelectionPrompt');
|
|
158
159
|
// Otherwise, add "click to start selecting range" prompt
|
|
159
160
|
} else {
|
|
160
|
-
rangeSelectionPrompt =
|
|
161
|
+
rangeSelectionPrompt = stringFormatter.format('startRangeSelectionPrompt');
|
|
161
162
|
}
|
|
162
163
|
}
|
|
163
164
|
|
|
@@ -283,12 +284,14 @@ export function useCalendarCell(props: AriaCalendarCellProps, state: CalendarSta
|
|
|
283
284
|
// Focus the button in the DOM when the state updates.
|
|
284
285
|
useEffect(() => {
|
|
285
286
|
if (isFocused && ref.current) {
|
|
287
|
+
focusWithoutScrolling(ref.current);
|
|
288
|
+
|
|
286
289
|
// Scroll into view if navigating with a keyboard, otherwise
|
|
287
290
|
// try not to shift the view under the user's mouse/finger.
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
ref.current.
|
|
291
|
+
// Only scroll the direct scroll parent, not the whole page, so
|
|
292
|
+
// we don't scroll to the bottom when opening date picker popover.
|
|
293
|
+
if (getInteractionModality() !== 'pointer') {
|
|
294
|
+
scrollIntoView(getScrollParent(ref.current) as HTMLElement, ref.current);
|
|
292
295
|
}
|
|
293
296
|
}
|
|
294
297
|
}, [isFocused, ref]);
|
package/src/useCalendarGrid.ts
CHANGED
|
@@ -10,10 +10,11 @@
|
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import {CalendarDate, startOfWeek} from '@internationalized/date';
|
|
13
|
+
import {CalendarDate, startOfWeek, today} from '@internationalized/date';
|
|
14
14
|
import {CalendarState, RangeCalendarState} from '@react-stately/calendar';
|
|
15
|
+
import {DOMAttributes} from '@react-types/shared';
|
|
15
16
|
import {hookData, useVisibleRangeDescription} from './utils';
|
|
16
|
-
import {
|
|
17
|
+
import {KeyboardEvent, useMemo} from 'react';
|
|
17
18
|
import {mergeProps, useLabels} from '@react-aria/utils';
|
|
18
19
|
import {useDateFormatter, useLocale} from '@react-aria/i18n';
|
|
19
20
|
|
|
@@ -34,9 +35,9 @@ export interface AriaCalendarGridProps {
|
|
|
34
35
|
|
|
35
36
|
export interface CalendarGridAria {
|
|
36
37
|
/** Props for the date grid element (e.g. `<table>`). */
|
|
37
|
-
gridProps:
|
|
38
|
+
gridProps: DOMAttributes,
|
|
38
39
|
/** Props for the grid header element (e.g. `<thead>`). */
|
|
39
|
-
headerProps:
|
|
40
|
+
headerProps: DOMAttributes,
|
|
40
41
|
/** A list of week day abbreviations formatted for the current locale, typically used in column headers. */
|
|
41
42
|
weekDays: string[]
|
|
42
43
|
}
|
|
@@ -63,22 +64,27 @@ export function useCalendarGrid(props: AriaCalendarGridProps, state: CalendarSta
|
|
|
63
64
|
break;
|
|
64
65
|
case 'PageUp':
|
|
65
66
|
e.preventDefault();
|
|
67
|
+
e.stopPropagation();
|
|
66
68
|
state.focusPreviousSection(e.shiftKey);
|
|
67
69
|
break;
|
|
68
70
|
case 'PageDown':
|
|
69
71
|
e.preventDefault();
|
|
72
|
+
e.stopPropagation();
|
|
70
73
|
state.focusNextSection(e.shiftKey);
|
|
71
74
|
break;
|
|
72
75
|
case 'End':
|
|
73
76
|
e.preventDefault();
|
|
77
|
+
e.stopPropagation();
|
|
74
78
|
state.focusSectionEnd();
|
|
75
79
|
break;
|
|
76
80
|
case 'Home':
|
|
77
81
|
e.preventDefault();
|
|
82
|
+
e.stopPropagation();
|
|
78
83
|
state.focusSectionStart();
|
|
79
84
|
break;
|
|
80
85
|
case 'ArrowLeft':
|
|
81
86
|
e.preventDefault();
|
|
87
|
+
e.stopPropagation();
|
|
82
88
|
if (direction === 'rtl') {
|
|
83
89
|
state.focusNextDay();
|
|
84
90
|
} else {
|
|
@@ -87,10 +93,12 @@ export function useCalendarGrid(props: AriaCalendarGridProps, state: CalendarSta
|
|
|
87
93
|
break;
|
|
88
94
|
case 'ArrowUp':
|
|
89
95
|
e.preventDefault();
|
|
96
|
+
e.stopPropagation();
|
|
90
97
|
state.focusPreviousRow();
|
|
91
98
|
break;
|
|
92
99
|
case 'ArrowRight':
|
|
93
100
|
e.preventDefault();
|
|
101
|
+
e.stopPropagation();
|
|
94
102
|
if (direction === 'rtl') {
|
|
95
103
|
state.focusPreviousDay();
|
|
96
104
|
} else {
|
|
@@ -99,6 +107,7 @@ export function useCalendarGrid(props: AriaCalendarGridProps, state: CalendarSta
|
|
|
99
107
|
break;
|
|
100
108
|
case 'ArrowDown':
|
|
101
109
|
e.preventDefault();
|
|
110
|
+
e.stopPropagation();
|
|
102
111
|
state.focusNextRow();
|
|
103
112
|
break;
|
|
104
113
|
case 'Escape':
|
|
@@ -122,13 +131,13 @@ export function useCalendarGrid(props: AriaCalendarGridProps, state: CalendarSta
|
|
|
122
131
|
let dayFormatter = useDateFormatter({weekday: 'narrow', timeZone: state.timeZone});
|
|
123
132
|
let {locale} = useLocale();
|
|
124
133
|
let weekDays = useMemo(() => {
|
|
125
|
-
let weekStart = startOfWeek(state.
|
|
134
|
+
let weekStart = startOfWeek(today(state.timeZone), locale);
|
|
126
135
|
return [...new Array(7).keys()].map((index) => {
|
|
127
136
|
let date = weekStart.add({days: index});
|
|
128
137
|
let dateDay = date.toDate(state.timeZone);
|
|
129
138
|
return dayFormatter.format(dateDay);
|
|
130
139
|
});
|
|
131
|
-
}, [
|
|
140
|
+
}, [locale, state.timeZone, dayFormatter]);
|
|
132
141
|
|
|
133
142
|
return {
|
|
134
143
|
gridProps: mergeProps(labelProps, {
|
package/src/useRangeCalendar.ts
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
import {CalendarAria, useCalendarBase} from './useCalendarBase';
|
|
14
14
|
import {DateValue, RangeCalendarProps} from '@react-types/calendar';
|
|
15
|
+
import {FocusableElement} from '@react-types/shared';
|
|
15
16
|
import {RangeCalendarState} from '@react-stately/calendar';
|
|
16
17
|
import {RefObject, useRef} from 'react';
|
|
17
18
|
import {useEvent} from '@react-aria/utils';
|
|
@@ -20,7 +21,7 @@ import {useEvent} from '@react-aria/utils';
|
|
|
20
21
|
* Provides the behavior and accessibility implementation for a range calendar component.
|
|
21
22
|
* A range calendar displays one or more date grids and allows users to select a contiguous range of dates.
|
|
22
23
|
*/
|
|
23
|
-
export function useRangeCalendar<T extends DateValue>(props: RangeCalendarProps<T>, state: RangeCalendarState, ref: RefObject<
|
|
24
|
+
export function useRangeCalendar<T extends DateValue>(props: RangeCalendarProps<T>, state: RangeCalendarState, ref: RefObject<FocusableElement>): CalendarAria {
|
|
24
25
|
let res = useCalendarBase(props, state);
|
|
25
26
|
|
|
26
27
|
// We need to ignore virtual pointer events from VoiceOver due to these bugs.
|
|
@@ -37,7 +38,7 @@ export function useRangeCalendar<T extends DateValue>(props: RangeCalendarProps<
|
|
|
37
38
|
|
|
38
39
|
// Stop range selection when pressing or releasing a pointer outside the calendar body,
|
|
39
40
|
// except when pressing the next or previous buttons to switch months.
|
|
40
|
-
let endDragging = e => {
|
|
41
|
+
let endDragging = (e: PointerEvent) => {
|
|
41
42
|
if (isVirtualClick.current) {
|
|
42
43
|
isVirtualClick.current = false;
|
|
43
44
|
return;
|
|
@@ -48,7 +49,7 @@ export function useRangeCalendar<T extends DateValue>(props: RangeCalendarProps<
|
|
|
48
49
|
return;
|
|
49
50
|
}
|
|
50
51
|
|
|
51
|
-
let target = e.target as
|
|
52
|
+
let target = e.target as Element;
|
|
52
53
|
let body = document.getElementById(res.calendarProps.id);
|
|
53
54
|
if (
|
|
54
55
|
body &&
|
package/src/utils.ts
CHANGED
|
@@ -12,9 +12,10 @@
|
|
|
12
12
|
|
|
13
13
|
import {CalendarDate, DateFormatter, endOfMonth, isSameDay, startOfMonth} from '@internationalized/date';
|
|
14
14
|
import {CalendarState, RangeCalendarState} from '@react-stately/calendar';
|
|
15
|
-
import {FormatMessage, useDateFormatter, useMessageFormatter} from '@react-aria/i18n';
|
|
16
15
|
// @ts-ignore
|
|
17
16
|
import intlMessages from '../intl/*.json';
|
|
17
|
+
import type {LocalizedStringFormatter} from '@internationalized/string';
|
|
18
|
+
import {useDateFormatter, useLocalizedStringFormatter} from '@react-aria/i18n';
|
|
18
19
|
import {useMemo} from 'react';
|
|
19
20
|
|
|
20
21
|
interface HookData {
|
|
@@ -26,8 +27,12 @@ interface HookData {
|
|
|
26
27
|
|
|
27
28
|
export const hookData = new WeakMap<CalendarState | RangeCalendarState, HookData>();
|
|
28
29
|
|
|
30
|
+
export function getEraFormat(date: CalendarDate): 'short' | undefined {
|
|
31
|
+
return date?.calendar.identifier === 'gregory' && date.era === 'BC' ? 'short' : undefined;
|
|
32
|
+
}
|
|
33
|
+
|
|
29
34
|
export function useSelectedDateDescription(state: CalendarState | RangeCalendarState) {
|
|
30
|
-
let
|
|
35
|
+
let stringFormatter = useLocalizedStringFormatter(intlMessages);
|
|
31
36
|
|
|
32
37
|
let start: CalendarDate, end: CalendarDate;
|
|
33
38
|
if ('highlightedRange' in state) {
|
|
@@ -37,7 +42,11 @@ export function useSelectedDateDescription(state: CalendarState | RangeCalendarS
|
|
|
37
42
|
}
|
|
38
43
|
|
|
39
44
|
let dateFormatter = useDateFormatter({
|
|
40
|
-
|
|
45
|
+
weekday: 'long',
|
|
46
|
+
month: 'long',
|
|
47
|
+
year: 'numeric',
|
|
48
|
+
day: 'numeric',
|
|
49
|
+
era: getEraFormat(start) || getEraFormat(end),
|
|
41
50
|
timeZone: state.timeZone
|
|
42
51
|
});
|
|
43
52
|
|
|
@@ -49,29 +58,33 @@ export function useSelectedDateDescription(state: CalendarState | RangeCalendarS
|
|
|
49
58
|
// otherwise include both dates.
|
|
50
59
|
if (isSameDay(start, end)) {
|
|
51
60
|
let date = dateFormatter.format(start.toDate(state.timeZone));
|
|
52
|
-
return
|
|
61
|
+
return stringFormatter.format('selectedDateDescription', {date});
|
|
53
62
|
} else {
|
|
54
|
-
let dateRange = formatRange(dateFormatter,
|
|
63
|
+
let dateRange = formatRange(dateFormatter, stringFormatter, start, end, state.timeZone);
|
|
55
64
|
|
|
56
|
-
return
|
|
65
|
+
return stringFormatter.format('selectedRangeDescription', {dateRange});
|
|
57
66
|
}
|
|
58
67
|
}
|
|
59
68
|
return '';
|
|
60
|
-
}, [start, end, anchorDate, state.timeZone,
|
|
69
|
+
}, [start, end, anchorDate, state.timeZone, stringFormatter, dateFormatter]);
|
|
61
70
|
}
|
|
62
71
|
|
|
63
72
|
export function useVisibleRangeDescription(startDate: CalendarDate, endDate: CalendarDate, timeZone: string, isAria: boolean) {
|
|
64
|
-
let
|
|
73
|
+
let stringFormatter = useLocalizedStringFormatter(intlMessages);
|
|
74
|
+
let era: any = getEraFormat(startDate) || getEraFormat(endDate);
|
|
65
75
|
let monthFormatter = useDateFormatter({
|
|
66
76
|
month: 'long',
|
|
67
77
|
year: 'numeric',
|
|
68
|
-
era
|
|
78
|
+
era,
|
|
69
79
|
calendar: startDate.calendar.identifier,
|
|
70
80
|
timeZone
|
|
71
81
|
});
|
|
72
82
|
|
|
73
83
|
let dateFormatter = useDateFormatter({
|
|
74
|
-
|
|
84
|
+
month: 'long',
|
|
85
|
+
year: 'numeric',
|
|
86
|
+
day: 'numeric',
|
|
87
|
+
era,
|
|
75
88
|
calendar: startDate.calendar.identifier,
|
|
76
89
|
timeZone
|
|
77
90
|
});
|
|
@@ -84,18 +97,18 @@ export function useVisibleRangeDescription(startDate: CalendarDate, endDate: Cal
|
|
|
84
97
|
return monthFormatter.format(startDate.toDate(timeZone));
|
|
85
98
|
} else if (isSameDay(endDate, endOfMonth(endDate))) {
|
|
86
99
|
return isAria
|
|
87
|
-
? formatRange(monthFormatter,
|
|
100
|
+
? formatRange(monthFormatter, stringFormatter, startDate, endDate, timeZone)
|
|
88
101
|
: monthFormatter.formatRange(startDate.toDate(timeZone), endDate.toDate(timeZone));
|
|
89
102
|
}
|
|
90
103
|
}
|
|
91
104
|
|
|
92
105
|
return isAria
|
|
93
|
-
? formatRange(dateFormatter,
|
|
106
|
+
? formatRange(dateFormatter, stringFormatter, startDate, endDate, timeZone)
|
|
94
107
|
: dateFormatter.formatRange(startDate.toDate(timeZone), endDate.toDate(timeZone));
|
|
95
|
-
}, [startDate, endDate, monthFormatter, dateFormatter,
|
|
108
|
+
}, [startDate, endDate, monthFormatter, dateFormatter, stringFormatter, timeZone, isAria]);
|
|
96
109
|
}
|
|
97
110
|
|
|
98
|
-
function formatRange(dateFormatter: DateFormatter,
|
|
111
|
+
function formatRange(dateFormatter: DateFormatter, stringFormatter: LocalizedStringFormatter, start: CalendarDate, end: CalendarDate, timeZone: string) {
|
|
99
112
|
let parts = dateFormatter.formatRangeToParts(start.toDate(timeZone), end.toDate(timeZone));
|
|
100
113
|
|
|
101
114
|
// Find the separator between the start and end date. This is determined
|
|
@@ -121,5 +134,5 @@ function formatRange(dateFormatter: DateFormatter, formatMessage: FormatMessage,
|
|
|
121
134
|
}
|
|
122
135
|
}
|
|
123
136
|
|
|
124
|
-
return
|
|
137
|
+
return stringFormatter.format('dateRange', {startDate: startValue, endDate: endValue});
|
|
125
138
|
}
|