@react-aria/datepicker 3.0.0-rc.0 → 3.0.0-rc.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.
@@ -17,7 +17,7 @@ import {CalendarProps} from '@react-types/calendar';
17
17
  import {createFocusManager} from '@react-aria/focus';
18
18
  import {DatePickerState} from '@react-stately/datepicker';
19
19
  import {filterDOMProps, mergeProps, useDescription, useId} from '@react-aria/utils';
20
- import {HTMLAttributes, RefObject} from 'react';
20
+ import {HTMLAttributes, RefObject, useMemo} from 'react';
21
21
  // @ts-ignore
22
22
  import intlMessages from '../intl/*.json';
23
23
  import {roleSymbol} from './useDateField';
@@ -68,6 +68,7 @@ export function useDatePicker<T extends DateValue>(props: AriaDatePickerProps<T>
68
68
  let descProps = useDescription(description);
69
69
  let ariaDescribedBy = [descProps['aria-describedby'], fieldProps['aria-describedby']].filter(Boolean).join(' ') || undefined;
70
70
  let domProps = filterDOMProps(props);
71
+ let focusManager = useMemo(() => createFocusManager(ref), [ref]);
71
72
 
72
73
  return {
73
74
  groupProps: mergeProps(domProps, groupProps, fieldProps, descProps, {
@@ -79,7 +80,6 @@ export function useDatePicker<T extends DateValue>(props: AriaDatePickerProps<T>
79
80
  labelProps: {
80
81
  ...labelProps,
81
82
  onClick: () => {
82
- let focusManager = createFocusManager(ref);
83
83
  focusManager.focusFirst();
84
84
  }
85
85
  },
@@ -106,7 +106,6 @@ export function useDatePicker<T extends DateValue>(props: AriaDatePickerProps<T>
106
106
  buttonProps: {
107
107
  ...descProps,
108
108
  id: buttonId,
109
- excludeFromTabOrder: true,
110
109
  'aria-haspopup': 'dialog',
111
110
  'aria-label': formatMessage('calendar'),
112
111
  'aria-labelledby': `${labelledBy} ${buttonId}`,
@@ -1,11 +1,15 @@
1
+ import {createFocusManager, getFocusableTreeWalker} from '@react-aria/focus';
1
2
  import {DateFieldState, DatePickerState, DateRangePickerState} from '@react-stately/datepicker';
2
- import {getFocusableTreeWalker} from '@react-aria/focus';
3
3
  import {KeyboardEvent} from '@react-types/shared';
4
4
  import {mergeProps} from '@react-aria/utils';
5
- import {RefObject} from 'react';
5
+ import {RefObject, useMemo} from 'react';
6
+ import {useLocale} from '@react-aria/i18n';
6
7
  import {usePress} from '@react-aria/interactions';
7
8
 
8
- export function useDatePickerGroup(state: DatePickerState | DateRangePickerState | DateFieldState, ref: RefObject<HTMLElement>) {
9
+ export function useDatePickerGroup(state: DatePickerState | DateRangePickerState | DateFieldState, ref: RefObject<HTMLElement>, disableArrowNavigation?: boolean) {
10
+ let {direction} = useLocale();
11
+ let focusManager = useMemo(() => createFocusManager(ref), [ref]);
12
+
9
13
  // Open the popover on alt + arrow down
10
14
  let onKeyDown = (e: KeyboardEvent) => {
11
15
  if (e.altKey && (e.key === 'ArrowDown' || e.key === 'ArrowUp') && 'setOpen' in state) {
@@ -13,6 +17,31 @@ export function useDatePickerGroup(state: DatePickerState | DateRangePickerState
13
17
  e.stopPropagation();
14
18
  state.setOpen(true);
15
19
  }
20
+
21
+ if (disableArrowNavigation) {
22
+ return;
23
+ }
24
+
25
+ switch (e.key) {
26
+ case 'ArrowLeft':
27
+ e.preventDefault();
28
+ e.stopPropagation();
29
+ if (direction === 'rtl') {
30
+ focusManager.focusNext();
31
+ } else {
32
+ focusManager.focusPrevious();
33
+ }
34
+ break;
35
+ case 'ArrowRight':
36
+ e.preventDefault();
37
+ e.stopPropagation();
38
+ if (direction === 'rtl') {
39
+ focusManager.focusPrevious();
40
+ } else {
41
+ focusManager.focusNext();
42
+ }
43
+ break;
44
+ }
16
45
  };
17
46
 
18
47
  // Focus the first placeholder segment from the end on mouse down/touch up in the field.
@@ -87,7 +87,11 @@ export function useDateRangePicker<T extends DateValue>(props: AriaDateRangePick
87
87
  });
88
88
 
89
89
  let ariaDescribedBy = [descProps['aria-describedby'], fieldProps['aria-describedby']].filter(Boolean).join(' ') || undefined;
90
- let focusManager = useMemo(() => createFocusManager(ref), [ref]);
90
+ let focusManager = useMemo(() => createFocusManager(ref, {
91
+ // Exclude the button from the focus manager.
92
+ accept: element => element.id !== buttonId
93
+ }), [ref, buttonId]);
94
+
91
95
  let commonFieldProps = {
92
96
  [focusManagerSymbol]: focusManager,
93
97
  [roleSymbol]: 'presentation',
@@ -121,7 +125,6 @@ export function useDateRangePicker<T extends DateValue>(props: AriaDateRangePick
121
125
  buttonProps: {
122
126
  ...descProps,
123
127
  id: buttonId,
124
- excludeFromTabOrder: true,
125
128
  'aria-haspopup': 'dialog',
126
129
  'aria-label': formatMessage('calendar'),
127
130
  'aria-labelledby': `${labelledBy} ${buttonId}`,
@@ -31,7 +31,7 @@ export interface DateSegmentAria {
31
31
  */
32
32
  export function useDateSegment(segment: DateSegment, state: DateFieldState, ref: RefObject<HTMLElement>): DateSegmentAria {
33
33
  let enteredKeys = useRef('');
34
- let {locale, direction} = useLocale();
34
+ let {locale} = useLocale();
35
35
  let displayNames = useDisplayNames();
36
36
  let {ariaLabel, ariaLabelledBy, ariaDescribedBy, focusManager} = hookData.get(state);
37
37
 
@@ -114,31 +114,13 @@ export function useDateSegment(segment: DateSegment, state: DateFieldState, ref:
114
114
  }
115
115
 
116
116
  switch (e.key) {
117
- case 'ArrowLeft':
118
- e.preventDefault();
119
- e.stopPropagation();
120
- if (direction === 'rtl') {
121
- focusManager.focusNext({tabbable: true});
122
- } else {
123
- focusManager.focusPrevious({tabbable: true});
124
- }
125
- break;
126
- case 'ArrowRight':
127
- e.preventDefault();
128
- e.stopPropagation();
129
- if (direction === 'rtl') {
130
- focusManager.focusPrevious({tabbable: true});
131
- } else {
132
- focusManager.focusNext({tabbable: true});
133
- }
134
- break;
135
117
  case 'Enter':
136
118
  e.preventDefault();
137
119
  e.stopPropagation();
138
120
  if (segment.isPlaceholder && !state.isReadOnly) {
139
121
  state.confirmPlaceholder(segment.type);
140
122
  }
141
- focusManager.focusNext({tabbable: true});
123
+ focusManager.focusNext();
142
124
  break;
143
125
  case 'Tab':
144
126
  break;
@@ -184,7 +166,7 @@ export function useDateSegment(segment: DateSegment, state: DateFieldState, ref:
184
166
  } else {
185
167
  break;
186
168
  }
187
- focusManager.focusNext({tabbable: true});
169
+ focusManager.focusNext();
188
170
  break;
189
171
  case 'day':
190
172
  case 'hour':
@@ -233,7 +215,7 @@ export function useDateSegment(segment: DateSegment, state: DateFieldState, ref:
233
215
  if (Number(numberValue + '0') > segment.maxValue || newValue.length >= String(segment.maxValue).length) {
234
216
  enteredKeys.current = '';
235
217
  if (shouldSetValue) {
236
- focusManager.focusNext({tabbable: true});
218
+ focusManager.focusNext();
237
219
  }
238
220
  } else {
239
221
  enteredKeys.current = newValue;
@@ -250,9 +232,11 @@ export function useDateSegment(segment: DateSegment, state: DateFieldState, ref:
250
232
  // Safari requires that a selection is set or it won't fire input events.
251
233
  // Since usePress disables text selection, this won't happen by default.
252
234
  ref.current.style.webkitUserSelect = 'text';
235
+ ref.current.style.userSelect = 'text';
253
236
  let selection = window.getSelection();
254
237
  selection.collapse(ref.current);
255
- ref.current.style.webkitUserSelect = '';
238
+ ref.current.style.webkitUserSelect = 'none';
239
+ ref.current.style.userSelect = 'none';
256
240
  };
257
241
 
258
242
  let compositionRef = useRef('');