@react-aria/datepicker 3.0.0-nightly.3180 → 3.0.0-rc.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/dist/main.js +80 -79
- package/dist/main.js.map +1 -1
- package/dist/module.js +80 -66
- package/dist/module.js.map +1 -1
- package/dist/types.d.ts +8 -6
- package/dist/types.d.ts.map +1 -1
- package/package.json +16 -16
- package/src/index.ts +7 -1
- package/src/useDateField.ts +14 -6
- package/src/useDatePicker.ts +10 -5
- package/src/useDateRangePicker.ts +10 -5
- package/src/useDateSegment.ts +12 -20
- package/src/useDisplayNames.ts +1 -0
package/src/index.ts
CHANGED
|
@@ -14,4 +14,10 @@ export {useDatePicker} from './useDatePicker';
|
|
|
14
14
|
export {useDateSegment} from './useDateSegment';
|
|
15
15
|
export {useDateField, useTimeField} from './useDateField';
|
|
16
16
|
export {useDateRangePicker} from './useDateRangePicker';
|
|
17
|
-
export
|
|
17
|
+
export {useDisplayNames} from './useDisplayNames';
|
|
18
|
+
|
|
19
|
+
export type {AriaDatePickerProps, AriaDateRangePickerProps} from '@react-types/datepicker';
|
|
20
|
+
export type {AriaDateFieldProps, DateFieldAria} from './useDateField';
|
|
21
|
+
export type {DatePickerAria} from './useDatePicker';
|
|
22
|
+
export type {DateRangePickerAria} from './useDateRangePicker';
|
|
23
|
+
export type {DateSegmentAria} from './useDateSegment';
|
package/src/useDateField.ts
CHANGED
|
@@ -13,16 +13,19 @@
|
|
|
13
13
|
import {AriaDatePickerProps, AriaTimeFieldProps, DateValue, TimeValue} from '@react-types/datepicker';
|
|
14
14
|
import {createFocusManager, FocusManager} from '@react-aria/focus';
|
|
15
15
|
import {DateFieldState} from '@react-stately/datepicker';
|
|
16
|
+
import {filterDOMProps, mergeProps, useDescription} from '@react-aria/utils';
|
|
16
17
|
import {HTMLAttributes, RefObject, useEffect, useMemo, useRef} from 'react';
|
|
17
|
-
|
|
18
|
+
// @ts-ignore
|
|
19
|
+
import intlMessages from '../intl/*.json';
|
|
18
20
|
import {useDatePickerGroup} from './useDatePickerGroup';
|
|
19
21
|
import {useField} from '@react-aria/label';
|
|
20
22
|
import {useFocusWithin} from '@react-aria/interactions';
|
|
23
|
+
import {useMessageFormatter} from '@react-aria/i18n';
|
|
21
24
|
|
|
22
25
|
// Allows this hook to also be used with TimeField
|
|
23
|
-
interface
|
|
26
|
+
export interface AriaDateFieldProps<T extends DateValue> extends Omit<AriaDatePickerProps<T>, 'value' | 'defaultValue' | 'onChange' | 'minValue' | 'maxValue' | 'placeholderValue'> {}
|
|
24
27
|
|
|
25
|
-
interface DateFieldAria {
|
|
28
|
+
export interface DateFieldAria {
|
|
26
29
|
/** Props for the field's visible label element, if any. */
|
|
27
30
|
labelProps: HTMLAttributes<HTMLElement>,
|
|
28
31
|
/** Props for the field grouping element. */
|
|
@@ -53,7 +56,7 @@ export const focusManagerSymbol = '__focusManager_' + Date.now();
|
|
|
53
56
|
* A date field allows users to enter and edit date and time values using a keyboard.
|
|
54
57
|
* Each part of a date value is displayed in an individually editable segment.
|
|
55
58
|
*/
|
|
56
|
-
export function useDateField<T extends DateValue>(props:
|
|
59
|
+
export function useDateField<T extends DateValue>(props: AriaDateFieldProps<T>, state: DateFieldState, ref: RefObject<HTMLElement>): DateFieldAria {
|
|
57
60
|
let {labelProps, fieldProps, descriptionProps, errorMessageProps} = useField({
|
|
58
61
|
...props,
|
|
59
62
|
labelElementType: 'span'
|
|
@@ -67,7 +70,11 @@ export function useDateField<T extends DateValue>(props: DateFieldProps<T>, stat
|
|
|
67
70
|
}
|
|
68
71
|
});
|
|
69
72
|
|
|
70
|
-
let
|
|
73
|
+
let formatMessage = useMessageFormatter(intlMessages);
|
|
74
|
+
let message = state.maxGranularity === 'hour' ? 'selectedTimeDescription' : 'selectedDateDescription';
|
|
75
|
+
let field = state.maxGranularity === 'hour' ? 'time' : 'date';
|
|
76
|
+
let description = state.value ? formatMessage(message, {[field]: state.formatValue({month: 'long'})}) : '';
|
|
77
|
+
let descProps = useDescription(description);
|
|
71
78
|
|
|
72
79
|
// If within a date picker or date range picker, the date field will have role="presentation" and an aria-describedby
|
|
73
80
|
// will be passed in that references the value (e.g. entire range). Otherwise, add the field's value description.
|
|
@@ -111,6 +118,7 @@ export function useDateField<T extends DateValue>(props: DateFieldProps<T>, stat
|
|
|
111
118
|
autoFocusRef.current = false;
|
|
112
119
|
}, [focusManager]);
|
|
113
120
|
|
|
121
|
+
let domProps = filterDOMProps(props);
|
|
114
122
|
return {
|
|
115
123
|
labelProps: {
|
|
116
124
|
...labelProps,
|
|
@@ -118,7 +126,7 @@ export function useDateField<T extends DateValue>(props: DateFieldProps<T>, stat
|
|
|
118
126
|
focusManager.focusFirst();
|
|
119
127
|
}
|
|
120
128
|
},
|
|
121
|
-
fieldProps: mergeProps(fieldDOMProps, groupProps, focusWithinProps),
|
|
129
|
+
fieldProps: mergeProps(domProps, fieldDOMProps, groupProps, focusWithinProps),
|
|
122
130
|
descriptionProps,
|
|
123
131
|
errorMessageProps
|
|
124
132
|
};
|
package/src/useDatePicker.ts
CHANGED
|
@@ -16,16 +16,16 @@ import {AriaDialogProps} from '@react-types/dialog';
|
|
|
16
16
|
import {CalendarProps} from '@react-types/calendar';
|
|
17
17
|
import {createFocusManager} from '@react-aria/focus';
|
|
18
18
|
import {DatePickerState} from '@react-stately/datepicker';
|
|
19
|
+
import {filterDOMProps, mergeProps, useDescription, useId} from '@react-aria/utils';
|
|
19
20
|
import {HTMLAttributes, RefObject} from 'react';
|
|
20
21
|
// @ts-ignore
|
|
21
22
|
import intlMessages from '../intl/*.json';
|
|
22
|
-
import {mergeProps, useDescription, useId} from '@react-aria/utils';
|
|
23
23
|
import {roleSymbol} from './useDateField';
|
|
24
24
|
import {useDatePickerGroup} from './useDatePickerGroup';
|
|
25
25
|
import {useField} from '@react-aria/label';
|
|
26
26
|
import {useLocale, useMessageFormatter} from '@react-aria/i18n';
|
|
27
27
|
|
|
28
|
-
interface DatePickerAria {
|
|
28
|
+
export interface DatePickerAria {
|
|
29
29
|
/** Props for the date picker's visible label element, if any. */
|
|
30
30
|
labelProps: HTMLAttributes<HTMLElement>,
|
|
31
31
|
/** Props for the grouping element containing the date field and button. */
|
|
@@ -63,11 +63,14 @@ export function useDatePicker<T extends DateValue>(props: AriaDatePickerProps<T>
|
|
|
63
63
|
let labelledBy = fieldProps['aria-labelledby'] || fieldProps.id;
|
|
64
64
|
|
|
65
65
|
let {locale} = useLocale();
|
|
66
|
-
let
|
|
66
|
+
let date = state.formatValue(locale, {month: 'long'});
|
|
67
|
+
let description = date ? formatMessage('selectedDateDescription', {date}) : '';
|
|
68
|
+
let descProps = useDescription(description);
|
|
67
69
|
let ariaDescribedBy = [descProps['aria-describedby'], fieldProps['aria-describedby']].filter(Boolean).join(' ') || undefined;
|
|
70
|
+
let domProps = filterDOMProps(props);
|
|
68
71
|
|
|
69
72
|
return {
|
|
70
|
-
groupProps: mergeProps(groupProps, fieldProps, descProps, {
|
|
73
|
+
groupProps: mergeProps(domProps, groupProps, fieldProps, descProps, {
|
|
71
74
|
role: 'group',
|
|
72
75
|
'aria-disabled': props.isDisabled || null,
|
|
73
76
|
'aria-labelledby': labelledBy,
|
|
@@ -123,7 +126,9 @@ export function useDatePicker<T extends DateValue>(props: AriaDatePickerProps<T>
|
|
|
123
126
|
isDisabled: props.isDisabled,
|
|
124
127
|
isReadOnly: props.isReadOnly,
|
|
125
128
|
isDateUnavailable: props.isDateUnavailable,
|
|
126
|
-
defaultFocusedValue: state.dateValue ? undefined : props.placeholderValue
|
|
129
|
+
defaultFocusedValue: state.dateValue ? undefined : props.placeholderValue,
|
|
130
|
+
validationState: state.validationState,
|
|
131
|
+
errorMessage: props.errorMessage
|
|
127
132
|
}
|
|
128
133
|
};
|
|
129
134
|
}
|
|
@@ -15,18 +15,18 @@ import {AriaDatePickerProps, AriaDateRangePickerProps, DateValue} from '@react-t
|
|
|
15
15
|
import {AriaDialogProps} from '@react-types/dialog';
|
|
16
16
|
import {createFocusManager} from '@react-aria/focus';
|
|
17
17
|
import {DateRangePickerState} from '@react-stately/datepicker';
|
|
18
|
+
import {filterDOMProps, mergeProps, useDescription, useId} from '@react-aria/utils';
|
|
18
19
|
import {focusManagerSymbol, roleSymbol} from './useDateField';
|
|
19
20
|
import {HTMLAttributes, RefObject, useMemo} from 'react';
|
|
20
21
|
// @ts-ignore
|
|
21
22
|
import intlMessages from '../intl/*.json';
|
|
22
|
-
import {mergeProps, useDescription, useId} from '@react-aria/utils';
|
|
23
23
|
import {RangeCalendarProps} from '@react-types/calendar';
|
|
24
24
|
import {useDatePickerGroup} from './useDatePickerGroup';
|
|
25
25
|
import {useField} from '@react-aria/label';
|
|
26
26
|
import {useFocusWithin} from '@react-aria/interactions';
|
|
27
27
|
import {useLocale, useMessageFormatter} from '@react-aria/i18n';
|
|
28
28
|
|
|
29
|
-
interface DateRangePickerAria {
|
|
29
|
+
export interface DateRangePickerAria {
|
|
30
30
|
/** Props for the date range picker's visible label element, if any. */
|
|
31
31
|
labelProps: HTMLAttributes<HTMLElement>,
|
|
32
32
|
/** Props for the grouping element containing the date fields and button. */
|
|
@@ -62,7 +62,8 @@ export function useDateRangePicker<T extends DateValue>(props: AriaDateRangePick
|
|
|
62
62
|
let labelledBy = fieldProps['aria-labelledby'] || fieldProps.id;
|
|
63
63
|
|
|
64
64
|
let {locale} = useLocale();
|
|
65
|
-
let
|
|
65
|
+
let range = state.formatValue(locale, {month: 'long'});
|
|
66
|
+
let description = range ? formatMessage('selectedRangeDescription', {startDate: range.start, endDate: range.end}) : '';
|
|
66
67
|
let descProps = useDescription(description);
|
|
67
68
|
|
|
68
69
|
let startFieldProps = {
|
|
@@ -103,8 +104,10 @@ export function useDateRangePicker<T extends DateValue>(props: AriaDateRangePick
|
|
|
103
104
|
validationState: state.validationState
|
|
104
105
|
};
|
|
105
106
|
|
|
107
|
+
let domProps = filterDOMProps(props);
|
|
108
|
+
|
|
106
109
|
return {
|
|
107
|
-
groupProps: mergeProps(groupProps, fieldProps, descProps, focusWithinProps, {
|
|
110
|
+
groupProps: mergeProps(domProps, groupProps, fieldProps, descProps, focusWithinProps, {
|
|
108
111
|
role: 'group',
|
|
109
112
|
'aria-disabled': props.isDisabled || null,
|
|
110
113
|
'aria-describedby': ariaDescribedBy
|
|
@@ -154,7 +157,9 @@ export function useDateRangePicker<T extends DateValue>(props: AriaDateRangePick
|
|
|
154
157
|
isReadOnly: props.isReadOnly,
|
|
155
158
|
isDateUnavailable: props.isDateUnavailable,
|
|
156
159
|
allowsNonContiguousRanges: props.allowsNonContiguousRanges,
|
|
157
|
-
defaultFocusedValue: state.dateRange ? undefined : props.placeholderValue
|
|
160
|
+
defaultFocusedValue: state.dateRange ? undefined : props.placeholderValue,
|
|
161
|
+
validationState: state.validationState,
|
|
162
|
+
errorMessage: props.errorMessage
|
|
158
163
|
}
|
|
159
164
|
};
|
|
160
165
|
}
|
package/src/useDateSegment.ts
CHANGED
|
@@ -17,10 +17,9 @@ import {NumberParser} from '@internationalized/number';
|
|
|
17
17
|
import React, {HTMLAttributes, RefObject, useMemo, useRef} from 'react';
|
|
18
18
|
import {useDateFormatter, useFilter, useLocale} from '@react-aria/i18n';
|
|
19
19
|
import {useDisplayNames} from './useDisplayNames';
|
|
20
|
-
import {usePress} from '@react-aria/interactions';
|
|
21
20
|
import {useSpinButton} from '@react-aria/spinbutton';
|
|
22
21
|
|
|
23
|
-
interface DateSegmentAria {
|
|
22
|
+
export interface DateSegmentAria {
|
|
24
23
|
/** Props for the segment element. */
|
|
25
24
|
segmentProps: HTMLAttributes<HTMLDivElement>
|
|
26
25
|
}
|
|
@@ -301,22 +300,6 @@ export function useDateSegment(segment: DateSegment, state: DateFieldState, ref:
|
|
|
301
300
|
}
|
|
302
301
|
});
|
|
303
302
|
|
|
304
|
-
// Focus on mouse down/touch up to match native textfield behavior.
|
|
305
|
-
// usePress handles canceling text selection.
|
|
306
|
-
let {pressProps} = usePress({
|
|
307
|
-
preventFocusOnPress: true,
|
|
308
|
-
onPressStart: (e) => {
|
|
309
|
-
if (e.pointerType === 'mouse') {
|
|
310
|
-
e.target.focus();
|
|
311
|
-
}
|
|
312
|
-
},
|
|
313
|
-
onPress(e) {
|
|
314
|
-
if (e.pointerType !== 'mouse') {
|
|
315
|
-
e.target.focus();
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
});
|
|
319
|
-
|
|
320
303
|
// For Android: prevent selection on long press.
|
|
321
304
|
useEvent(ref, 'selectstart', e => {
|
|
322
305
|
e.preventDefault();
|
|
@@ -360,7 +343,7 @@ export function useDateSegment(segment: DateSegment, state: DateFieldState, ref:
|
|
|
360
343
|
}
|
|
361
344
|
|
|
362
345
|
return {
|
|
363
|
-
segmentProps: mergeProps(spinButtonProps,
|
|
346
|
+
segmentProps: mergeProps(spinButtonProps, labelProps, {
|
|
364
347
|
id,
|
|
365
348
|
...touchPropOverrides,
|
|
366
349
|
'aria-invalid': state.validationState === 'invalid' ? 'true' : undefined,
|
|
@@ -379,7 +362,16 @@ export function useDateSegment(segment: DateSegment, state: DateFieldState, ref:
|
|
|
379
362
|
onKeyDown,
|
|
380
363
|
onFocus,
|
|
381
364
|
style: {
|
|
382
|
-
caretColor: 'transparent'
|
|
365
|
+
caretColor: 'transparent',
|
|
366
|
+
userSelect: 'none',
|
|
367
|
+
WebkitUserSelect: 'none'
|
|
368
|
+
},
|
|
369
|
+
// Prevent pointer events from reaching useDatePickerGroup, and allow native browser behavior to focus the segment.
|
|
370
|
+
onPointerDown(e) {
|
|
371
|
+
e.stopPropagation();
|
|
372
|
+
},
|
|
373
|
+
onMouseDown(e) {
|
|
374
|
+
e.stopPropagation();
|
|
383
375
|
}
|
|
384
376
|
})
|
|
385
377
|
};
|