@react-aria/table 3.8.2-nightly.3749 → 3.8.2-nightly.3757

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.
@@ -13,13 +13,13 @@
13
13
  import {ChangeEvent, Key, RefObject, useCallback, useRef} from 'react';
14
14
  import {DOMAttributes, FocusableElement} from '@react-types/shared';
15
15
  import {focusSafely} from '@react-aria/focus';
16
- import {focusWithoutScrolling, mergeProps, useId} from '@react-aria/utils';
16
+ import {focusWithoutScrolling, mergeProps, useDescription, useId} from '@react-aria/utils';
17
17
  import {getColumnHeaderId} from './utils';
18
18
  import {GridNode} from '@react-types/grid';
19
19
  // @ts-ignore
20
20
  import intlMessages from '../intl/*.json';
21
21
  import {TableColumnResizeState} from '@react-stately/table';
22
- import {useKeyboard, useMove, usePress} from '@react-aria/interactions';
22
+ import {useInteractionModality, useKeyboard, useMove, usePress} from '@react-aria/interactions';
23
23
  import {useLocale, useLocalizedStringFormatter} from '@react-aria/i18n';
24
24
 
25
25
  export interface TableColumnResizeAria {
@@ -36,7 +36,8 @@ export interface AriaTableColumnResizeProps<T> {
36
36
  label: string,
37
37
  /**
38
38
  * Ref to the trigger if resizing was started from a column header menu. If it's provided,
39
- * focus will be returned there when resizing is done.
39
+ * focus will be returned there when resizing is done. If it isn't provided, it is assumed that the resizer is
40
+ * visible at all time and keyboard resizing is started via pressing Enter on the resizer and not on focus.
40
41
  * */
41
42
  triggerRef?: RefObject<FocusableElement>,
42
43
  /** If resizing is disabled. */
@@ -63,14 +64,31 @@ export function useTableColumnResize<T>(props: AriaTableColumnResizeProps<T>, st
63
64
  let id = useId();
64
65
  let isResizing = useRef(false);
65
66
  let lastSize = useRef(null);
67
+ let editModeEnabled = state.tableState.isKeyboardNavigationDisabled;
66
68
 
67
69
  let {direction} = useLocale();
68
70
  let {keyboardProps} = useKeyboard({
69
71
  onKeyDown: (e) => {
70
- if (triggerRef?.current && (e.key === 'Escape' || e.key === 'Enter' || e.key === ' ' || e.key === 'Tab')) {
71
- e.preventDefault();
72
- // switch focus back to the column header on anything that ends edit mode
73
- focusSafely(triggerRef.current);
72
+ let resizeOnFocus = !!triggerRef?.current;
73
+ if (editModeEnabled) {
74
+ if (e.key === 'Escape' || e.key === 'Enter' || e.key === ' ' || e.key === 'Tab') {
75
+ e.preventDefault();
76
+ if (resizeOnFocus) {
77
+ // switch focus back to the column header on anything that ends edit mode
78
+ focusSafely(triggerRef.current);
79
+ } else {
80
+ endResize(item);
81
+ state.tableState.setKeyboardNavigationDisabled(false);
82
+ }
83
+ }
84
+ } else if (!resizeOnFocus) {
85
+ // Continue propagation on keydown events so they still bubbles to useSelectableCollection and are handled there
86
+ e.continuePropagation();
87
+
88
+ if (e.key === 'Enter') {
89
+ startResize(item);
90
+ state.tableState.setKeyboardNavigationDisabled(true);
91
+ }
74
92
  }
75
93
  }
76
94
  });
@@ -91,10 +109,11 @@ export function useTableColumnResize<T>(props: AriaTableColumnResizeProps<T>, st
91
109
  }, [onResize, state]);
92
110
 
93
111
  let endResize = useCallback((item) => {
94
- if (lastSize.current == null) {
95
- lastSize.current = state.updateResizedColumns(item.key, state.getColumnWidth(item.key));
96
- }
97
112
  if (isResizing.current) {
113
+ if (lastSize.current == null) {
114
+ lastSize.current = state.updateResizedColumns(item.key, state.getColumnWidth(item.key));
115
+ }
116
+
98
117
  state.endResize();
99
118
  onResizeEnd?.(lastSize.current);
100
119
  }
@@ -126,20 +145,31 @@ export function useTableColumnResize<T>(props: AriaTableColumnResizeProps<T>, st
126
145
  }
127
146
  },
128
147
  onMoveEnd(e) {
148
+ let resizeOnFocus = !!triggerRef?.current;
129
149
  let {pointerType} = e;
130
150
  columnResizeWidthRef.current = 0;
131
- if (pointerType === 'mouse') {
151
+ if (pointerType === 'mouse' || (pointerType === 'touch' && !resizeOnFocus)) {
132
152
  endResize(item);
133
153
  }
134
154
  }
135
155
  });
136
156
 
157
+ let onKeyDown = useCallback((e) => {
158
+ if (editModeEnabled) {
159
+ moveProps.onKeyDown(e);
160
+ }
161
+ }, [editModeEnabled, moveProps]);
162
+
163
+
137
164
  let min = Math.floor(state.getColumnMinWidth(item.key));
138
165
  let max = Math.floor(state.getColumnMaxWidth(item.key));
139
166
  if (max === Infinity) {
140
167
  max = Number.MAX_SAFE_INTEGER;
141
168
  }
142
169
  let value = Math.floor(state.getColumnWidth(item.key));
170
+ let modality = useInteractionModality();
171
+ let description = triggerRef?.current == null && (modality === 'keyboard' || modality === 'virtual') && !isResizing.current ? stringFormatter.format('resizerDescription') : undefined;
172
+ let descriptionProps = useDescription(description);
143
173
  let ariaProps = {
144
174
  'aria-label': props.label,
145
175
  'aria-orientation': 'horizontal' as 'horizontal',
@@ -148,7 +178,8 @@ export function useTableColumnResize<T>(props: AriaTableColumnResizeProps<T>, st
148
178
  'type': 'range',
149
179
  min,
150
180
  max,
151
- value
181
+ value,
182
+ ...descriptionProps
152
183
  };
153
184
 
154
185
  const focusInput = useCallback(() => {
@@ -175,21 +206,28 @@ export function useTableColumnResize<T>(props: AriaTableColumnResizeProps<T>, st
175
206
  return;
176
207
  }
177
208
  if (e.pointerType === 'virtual' && state.resizingColumn != null) {
209
+ let resizeOnFocus = !!triggerRef?.current;
178
210
  endResize(item);
179
- if (triggerRef?.current) {
211
+ if (resizeOnFocus) {
180
212
  focusSafely(triggerRef.current);
181
213
  }
182
214
  return;
183
215
  }
216
+
217
+ // Sometimes onPress won't trigger for quick taps on mobile so we want to focus the input so blurring away
218
+ // can cancel resize mode for us.
184
219
  focusInput();
220
+
221
+ // If resizer is always visible, mobile screenreader user can access the visually hidden resizer directly and thus we don't need
222
+ // to handle a virtual click to start the resizer.
223
+ if (e.pointerType !== 'virtual') {
224
+ startResize(item);
225
+ }
185
226
  },
186
227
  onPress: (e) => {
187
- if (e.pointerType === 'touch') {
188
- focusInput();
189
- } else if (e.pointerType !== 'virtual') {
190
- if (triggerRef?.current) {
191
- focusSafely(triggerRef.current);
192
- }
228
+ let resizeOnFocus = !!triggerRef?.current;
229
+ if (((e.pointerType === 'touch' && !resizeOnFocus) || e.pointerType === 'mouse') && state.resizingColumn != null) {
230
+ endResize(item);
193
231
  }
194
232
  }
195
233
  });
@@ -197,17 +235,24 @@ export function useTableColumnResize<T>(props: AriaTableColumnResizeProps<T>, st
197
235
  return {
198
236
  resizerProps: mergeProps(
199
237
  keyboardProps,
200
- moveProps,
238
+ {...moveProps, onKeyDown},
201
239
  pressProps
202
240
  ),
203
241
  inputProps: mergeProps(
204
242
  {
205
243
  id,
244
+ // Override browser default margin. Without this, scrollIntoViewport will think we need to scroll the input into view
245
+ style: {
246
+ margin: '0px'
247
+ },
206
248
  onFocus: () => {
207
- // useMove calls onMoveStart for every keypress, but we want resize start to only be called when we start resize mode
208
- // call instead during focus and blur
209
- startResize(item);
210
- state.tableState.setKeyboardNavigationDisabled(true);
249
+ let resizeOnFocus = !!triggerRef?.current;
250
+ if (resizeOnFocus) {
251
+ // useMove calls onMoveStart for every keypress, but we want resize start to only be called when we start resize mode
252
+ // call instead during focus and blur
253
+ startResize(item);
254
+ state.tableState.setKeyboardNavigationDisabled(true);
255
+ }
211
256
  },
212
257
  onBlur: () => {
213
258
  endResize(item);