@react-aria/selection 3.4.1 → 3.7.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 +288 -168
- package/dist/main.js.map +1 -1
- package/dist/module.js +279 -166
- package/dist/module.js.map +1 -1
- package/dist/types.d.ts +19 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +9 -9
- package/src/useSelectableCollection.ts +160 -93
- package/src/useSelectableItem.ts +106 -15
- package/src/useSelectableList.ts +4 -43
- package/src/utils.ts +34 -0
package/dist/module.js
CHANGED
|
@@ -1,9 +1,24 @@
|
|
|
1
|
+
import { useLongPress, usePress } from "@react-aria/interactions";
|
|
1
2
|
import { useLocale, useCollator } from "@react-aria/i18n";
|
|
2
|
-
import {
|
|
3
|
+
import { focusWithoutScrolling, mergeProps, useEvent, isAppleDevice, isMac } from "@react-aria/utils";
|
|
3
4
|
import { focusSafely, getFocusableTreeWalker } from "@react-aria/focus";
|
|
4
5
|
import { useEffect, useRef, useMemo } from "react";
|
|
5
6
|
import _babelRuntimeHelpersEsmExtends from "@babel/runtime/helpers/esm/extends";
|
|
6
7
|
|
|
8
|
+
function $d9657c365c2f735bcaf048eee8599a4a$export$isNonContiguousSelectionModifier(e) {
|
|
9
|
+
// Ctrl + Arrow Up/Arrow Down has a system wide meaning on macOS, so use Alt instead.
|
|
10
|
+
// On Windows and Ubuntu, Alt + Space has a system wide meaning.
|
|
11
|
+
return isAppleDevice() ? e.altKey : e.ctrlKey;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function $d9657c365c2f735bcaf048eee8599a4a$export$isCtrlKeyPressed(e) {
|
|
15
|
+
if (isMac()) {
|
|
16
|
+
return e.metaKey;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return e.ctrlKey;
|
|
20
|
+
}
|
|
21
|
+
|
|
7
22
|
/**
|
|
8
23
|
* Handles typeahead interactions with collections.
|
|
9
24
|
*/
|
|
@@ -81,14 +96,6 @@ function $c78d7fa5f7d5832f9b4f97b33a679865$var$getStringForKey(key) {
|
|
|
81
96
|
return '';
|
|
82
97
|
}
|
|
83
98
|
|
|
84
|
-
function $a9b9aa71af07c56ab1d89ca45381f4b$var$isCtrlKeyPressed(e) {
|
|
85
|
-
if (isMac()) {
|
|
86
|
-
return e.metaKey;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
return e.ctrlKey;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
99
|
/**
|
|
93
100
|
* Handles interactions with selectable collections.
|
|
94
101
|
*/
|
|
@@ -101,48 +108,54 @@ export function useSelectableCollection(options) {
|
|
|
101
108
|
shouldFocusWrap = false,
|
|
102
109
|
disallowEmptySelection = false,
|
|
103
110
|
disallowSelectAll = false,
|
|
104
|
-
selectOnFocus =
|
|
111
|
+
selectOnFocus = manager.selectionBehavior === 'replace',
|
|
105
112
|
disallowTypeAhead = false,
|
|
106
113
|
shouldUseVirtualFocus,
|
|
107
|
-
allowsTabNavigation = false
|
|
114
|
+
allowsTabNavigation = false,
|
|
115
|
+
isVirtualized,
|
|
116
|
+
// If no scrollRef is provided, assume the collection ref is the scrollable region
|
|
117
|
+
scrollRef = ref
|
|
108
118
|
} = options;
|
|
109
119
|
let {
|
|
110
120
|
direction
|
|
111
121
|
} = useLocale();
|
|
112
122
|
|
|
113
123
|
let onKeyDown = e => {
|
|
114
|
-
//
|
|
115
|
-
|
|
124
|
+
// Prevent option + tab from doing anything since it doesn't move focus to the cells, only buttons/checkboxes
|
|
125
|
+
if (e.altKey && e.key === 'Tab') {
|
|
126
|
+
e.preventDefault();
|
|
127
|
+
} // Keyboard events bubble through portals. Don't handle keyboard events
|
|
116
128
|
// for elements outside the collection (e.g. menus).
|
|
117
|
-
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
if (!ref.current.contains(e.target)) {
|
|
118
132
|
return;
|
|
119
133
|
}
|
|
120
134
|
|
|
135
|
+
const navigateToKey = (key, childFocus) => {
|
|
136
|
+
if (key != null) {
|
|
137
|
+
manager.setFocusedKey(key, childFocus);
|
|
138
|
+
|
|
139
|
+
if (e.shiftKey && manager.selectionMode === 'multiple') {
|
|
140
|
+
manager.extendSelection(key);
|
|
141
|
+
} else if (selectOnFocus && !$d9657c365c2f735bcaf048eee8599a4a$export$isNonContiguousSelectionModifier(e)) {
|
|
142
|
+
manager.replaceSelection(key);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
|
|
121
147
|
switch (e.key) {
|
|
122
148
|
case 'ArrowDown':
|
|
123
149
|
{
|
|
124
150
|
if (delegate.getKeyBelow) {
|
|
125
151
|
e.preventDefault();
|
|
126
|
-
let nextKey = manager.focusedKey != null ? delegate.getKeyBelow(manager.focusedKey) : delegate.getFirstKey();
|
|
127
|
-
|
|
128
|
-
if (nextKey != null) {
|
|
129
|
-
manager.setFocusedKey(nextKey);
|
|
130
|
-
|
|
131
|
-
if (manager.selectionMode === 'single' && selectOnFocus) {
|
|
132
|
-
manager.replaceSelection(nextKey);
|
|
133
|
-
}
|
|
134
|
-
} else if (shouldFocusWrap) {
|
|
135
|
-
let wrapKey = delegate.getFirstKey(manager.focusedKey);
|
|
136
|
-
manager.setFocusedKey(wrapKey);
|
|
152
|
+
let nextKey = manager.focusedKey != null ? delegate.getKeyBelow(manager.focusedKey) : delegate.getFirstKey == null ? void 0 : delegate.getFirstKey();
|
|
137
153
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
}
|
|
154
|
+
if (nextKey == null && shouldFocusWrap) {
|
|
155
|
+
nextKey = delegate.getFirstKey == null ? void 0 : delegate.getFirstKey(manager.focusedKey);
|
|
141
156
|
}
|
|
142
157
|
|
|
143
|
-
|
|
144
|
-
manager.extendSelection(nextKey);
|
|
145
|
-
}
|
|
158
|
+
navigateToKey(nextKey);
|
|
146
159
|
}
|
|
147
160
|
|
|
148
161
|
break;
|
|
@@ -152,26 +165,13 @@ export function useSelectableCollection(options) {
|
|
|
152
165
|
{
|
|
153
166
|
if (delegate.getKeyAbove) {
|
|
154
167
|
e.preventDefault();
|
|
155
|
-
let nextKey = manager.focusedKey != null ? delegate.getKeyAbove(manager.focusedKey) : delegate.getLastKey();
|
|
168
|
+
let nextKey = manager.focusedKey != null ? delegate.getKeyAbove(manager.focusedKey) : delegate.getLastKey == null ? void 0 : delegate.getLastKey();
|
|
156
169
|
|
|
157
|
-
if (nextKey
|
|
158
|
-
manager.
|
|
159
|
-
|
|
160
|
-
if (manager.selectionMode === 'single' && selectOnFocus) {
|
|
161
|
-
manager.replaceSelection(nextKey);
|
|
162
|
-
}
|
|
163
|
-
} else if (shouldFocusWrap) {
|
|
164
|
-
let wrapKey = delegate.getLastKey(manager.focusedKey);
|
|
165
|
-
manager.setFocusedKey(wrapKey);
|
|
166
|
-
|
|
167
|
-
if (manager.selectionMode === 'single' && selectOnFocus) {
|
|
168
|
-
manager.replaceSelection(wrapKey);
|
|
169
|
-
}
|
|
170
|
+
if (nextKey == null && shouldFocusWrap) {
|
|
171
|
+
nextKey = delegate.getLastKey == null ? void 0 : delegate.getLastKey(manager.focusedKey);
|
|
170
172
|
}
|
|
171
173
|
|
|
172
|
-
|
|
173
|
-
manager.extendSelection(nextKey);
|
|
174
|
-
}
|
|
174
|
+
navigateToKey(nextKey);
|
|
175
175
|
}
|
|
176
176
|
|
|
177
177
|
break;
|
|
@@ -182,18 +182,7 @@ export function useSelectableCollection(options) {
|
|
|
182
182
|
if (delegate.getKeyLeftOf) {
|
|
183
183
|
e.preventDefault();
|
|
184
184
|
let nextKey = delegate.getKeyLeftOf(manager.focusedKey);
|
|
185
|
-
|
|
186
|
-
if (nextKey != null) {
|
|
187
|
-
manager.setFocusedKey(nextKey, direction === 'rtl' ? 'first' : 'last');
|
|
188
|
-
|
|
189
|
-
if (manager.selectionMode === 'single' && selectOnFocus) {
|
|
190
|
-
manager.replaceSelection(nextKey);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
if (e.shiftKey && manager.selectionMode === 'multiple') {
|
|
195
|
-
manager.extendSelection(nextKey);
|
|
196
|
-
}
|
|
185
|
+
navigateToKey(nextKey, direction === 'rtl' ? 'first' : 'last');
|
|
197
186
|
}
|
|
198
187
|
|
|
199
188
|
break;
|
|
@@ -204,18 +193,7 @@ export function useSelectableCollection(options) {
|
|
|
204
193
|
if (delegate.getKeyRightOf) {
|
|
205
194
|
e.preventDefault();
|
|
206
195
|
let nextKey = delegate.getKeyRightOf(manager.focusedKey);
|
|
207
|
-
|
|
208
|
-
if (nextKey != null) {
|
|
209
|
-
manager.setFocusedKey(nextKey, direction === 'rtl' ? 'last' : 'first');
|
|
210
|
-
|
|
211
|
-
if (manager.selectionMode === 'single' && selectOnFocus) {
|
|
212
|
-
manager.replaceSelection(nextKey);
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
if (e.shiftKey && manager.selectionMode === 'multiple') {
|
|
217
|
-
manager.extendSelection(nextKey);
|
|
218
|
-
}
|
|
196
|
+
navigateToKey(nextKey, direction === 'rtl' ? 'last' : 'first');
|
|
219
197
|
}
|
|
220
198
|
|
|
221
199
|
break;
|
|
@@ -224,15 +202,13 @@ export function useSelectableCollection(options) {
|
|
|
224
202
|
case 'Home':
|
|
225
203
|
if (delegate.getFirstKey) {
|
|
226
204
|
e.preventDefault();
|
|
227
|
-
let firstKey = delegate.getFirstKey(manager.focusedKey, $
|
|
205
|
+
let firstKey = delegate.getFirstKey(manager.focusedKey, $d9657c365c2f735bcaf048eee8599a4a$export$isCtrlKeyPressed(e));
|
|
228
206
|
manager.setFocusedKey(firstKey);
|
|
229
207
|
|
|
230
|
-
if (manager.selectionMode === '
|
|
231
|
-
manager.replaceSelection(firstKey);
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
if ($a9b9aa71af07c56ab1d89ca45381f4b$var$isCtrlKeyPressed(e) && e.shiftKey && manager.selectionMode === 'multiple') {
|
|
208
|
+
if ($d9657c365c2f735bcaf048eee8599a4a$export$isCtrlKeyPressed(e) && e.shiftKey && manager.selectionMode === 'multiple') {
|
|
235
209
|
manager.extendSelection(firstKey);
|
|
210
|
+
} else if (selectOnFocus) {
|
|
211
|
+
manager.replaceSelection(firstKey);
|
|
236
212
|
}
|
|
237
213
|
}
|
|
238
214
|
|
|
@@ -241,15 +217,13 @@ export function useSelectableCollection(options) {
|
|
|
241
217
|
case 'End':
|
|
242
218
|
if (delegate.getLastKey) {
|
|
243
219
|
e.preventDefault();
|
|
244
|
-
let lastKey = delegate.getLastKey(manager.focusedKey, $
|
|
220
|
+
let lastKey = delegate.getLastKey(manager.focusedKey, $d9657c365c2f735bcaf048eee8599a4a$export$isCtrlKeyPressed(e));
|
|
245
221
|
manager.setFocusedKey(lastKey);
|
|
246
222
|
|
|
247
|
-
if (manager.selectionMode === '
|
|
248
|
-
manager.replaceSelection(lastKey);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
if ($a9b9aa71af07c56ab1d89ca45381f4b$var$isCtrlKeyPressed(e) && e.shiftKey && manager.selectionMode === 'multiple') {
|
|
223
|
+
if ($d9657c365c2f735bcaf048eee8599a4a$export$isCtrlKeyPressed(e) && e.shiftKey && manager.selectionMode === 'multiple') {
|
|
252
224
|
manager.extendSelection(lastKey);
|
|
225
|
+
} else if (selectOnFocus) {
|
|
226
|
+
manager.replaceSelection(lastKey);
|
|
253
227
|
}
|
|
254
228
|
}
|
|
255
229
|
|
|
@@ -259,14 +233,7 @@ export function useSelectableCollection(options) {
|
|
|
259
233
|
if (delegate.getKeyPageBelow) {
|
|
260
234
|
e.preventDefault();
|
|
261
235
|
let nextKey = delegate.getKeyPageBelow(manager.focusedKey);
|
|
262
|
-
|
|
263
|
-
if (nextKey != null) {
|
|
264
|
-
manager.setFocusedKey(nextKey);
|
|
265
|
-
|
|
266
|
-
if (e.shiftKey && manager.selectionMode === 'multiple') {
|
|
267
|
-
manager.extendSelection(nextKey);
|
|
268
|
-
}
|
|
269
|
-
}
|
|
236
|
+
navigateToKey(nextKey);
|
|
270
237
|
}
|
|
271
238
|
|
|
272
239
|
break;
|
|
@@ -275,20 +242,13 @@ export function useSelectableCollection(options) {
|
|
|
275
242
|
if (delegate.getKeyPageAbove) {
|
|
276
243
|
e.preventDefault();
|
|
277
244
|
let nextKey = delegate.getKeyPageAbove(manager.focusedKey);
|
|
278
|
-
|
|
279
|
-
if (nextKey != null) {
|
|
280
|
-
manager.setFocusedKey(nextKey);
|
|
281
|
-
|
|
282
|
-
if (e.shiftKey && manager.selectionMode === 'multiple') {
|
|
283
|
-
manager.extendSelection(nextKey);
|
|
284
|
-
}
|
|
285
|
-
}
|
|
245
|
+
navigateToKey(nextKey);
|
|
286
246
|
}
|
|
287
247
|
|
|
288
248
|
break;
|
|
289
249
|
|
|
290
250
|
case 'a':
|
|
291
|
-
if ($
|
|
251
|
+
if ($d9657c365c2f735bcaf048eee8599a4a$export$isCtrlKeyPressed(e) && manager.selectionMode === 'multiple' && disallowSelectAll !== true) {
|
|
292
252
|
e.preventDefault();
|
|
293
253
|
manager.selectAll();
|
|
294
254
|
}
|
|
@@ -331,7 +291,7 @@ export function useSelectableCollection(options) {
|
|
|
331
291
|
} while (last);
|
|
332
292
|
|
|
333
293
|
if (next && !next.contains(document.activeElement)) {
|
|
334
|
-
next
|
|
294
|
+
focusWithoutScrolling(next);
|
|
335
295
|
}
|
|
336
296
|
}
|
|
337
297
|
|
|
@@ -339,7 +299,19 @@ export function useSelectableCollection(options) {
|
|
|
339
299
|
}
|
|
340
300
|
}
|
|
341
301
|
}
|
|
342
|
-
};
|
|
302
|
+
}; // Store the scroll position so we can restore it later.
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
let scrollPos = useRef({
|
|
306
|
+
top: 0,
|
|
307
|
+
left: 0
|
|
308
|
+
});
|
|
309
|
+
useEvent(scrollRef, 'scroll', isVirtualized ? null : () => {
|
|
310
|
+
scrollPos.current = {
|
|
311
|
+
top: scrollRef.current.scrollTop,
|
|
312
|
+
left: scrollRef.current.scrollLeft
|
|
313
|
+
};
|
|
314
|
+
});
|
|
343
315
|
|
|
344
316
|
let onFocus = e => {
|
|
345
317
|
if (manager.isFocused) {
|
|
@@ -359,19 +331,41 @@ export function useSelectableCollection(options) {
|
|
|
359
331
|
manager.setFocused(true);
|
|
360
332
|
|
|
361
333
|
if (manager.focusedKey == null) {
|
|
362
|
-
|
|
334
|
+
let navigateToFirstKey = key => {
|
|
335
|
+
if (key != null) {
|
|
336
|
+
manager.setFocusedKey(key);
|
|
337
|
+
|
|
338
|
+
if (selectOnFocus) {
|
|
339
|
+
manager.replaceSelection(key);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}; // If the user hasn't yet interacted with the collection, there will be no focusedKey set.
|
|
363
343
|
// Attempt to detect whether the user is tabbing forward or backward into the collection
|
|
364
344
|
// and either focus the first or last item accordingly.
|
|
345
|
+
|
|
346
|
+
|
|
365
347
|
let relatedTarget = e.relatedTarget;
|
|
366
348
|
|
|
367
349
|
if (relatedTarget && e.currentTarget.compareDocumentPosition(relatedTarget) & Node.DOCUMENT_POSITION_FOLLOWING) {
|
|
368
350
|
var _manager$lastSelected;
|
|
369
351
|
|
|
370
|
-
|
|
352
|
+
navigateToFirstKey((_manager$lastSelected = manager.lastSelectedKey) != null ? _manager$lastSelected : delegate.getLastKey());
|
|
371
353
|
} else {
|
|
372
354
|
var _manager$firstSelecte;
|
|
373
355
|
|
|
374
|
-
|
|
356
|
+
navigateToFirstKey((_manager$firstSelecte = manager.firstSelectedKey) != null ? _manager$firstSelecte : delegate.getFirstKey());
|
|
357
|
+
}
|
|
358
|
+
} else if (!isVirtualized) {
|
|
359
|
+
// Restore the scroll position to what it was before.
|
|
360
|
+
scrollRef.current.scrollTop = scrollPos.current.top;
|
|
361
|
+
scrollRef.current.scrollLeft = scrollPos.current.left; // Refocus and scroll the focused item into view if it exists within the scrollable region.
|
|
362
|
+
|
|
363
|
+
let element = scrollRef.current.querySelector("[data-key=\"" + manager.focusedKey + "\"]");
|
|
364
|
+
|
|
365
|
+
if (element) {
|
|
366
|
+
// This prevents a flash of focus on the first/last element in the collection
|
|
367
|
+
focusWithoutScrolling(element);
|
|
368
|
+
$a9b9aa71af07c56ab1d89ca45381f4b$var$scrollIntoView(scrollRef.current, element);
|
|
375
369
|
}
|
|
376
370
|
}
|
|
377
371
|
};
|
|
@@ -383,8 +377,9 @@ export function useSelectableCollection(options) {
|
|
|
383
377
|
}
|
|
384
378
|
};
|
|
385
379
|
|
|
380
|
+
const autoFocusRef = useRef(autoFocus);
|
|
386
381
|
useEffect(() => {
|
|
387
|
-
if (
|
|
382
|
+
if (autoFocusRef.current) {
|
|
388
383
|
let focusedKey = null; // Check focus strategy to determine which item to focus
|
|
389
384
|
|
|
390
385
|
if (autoFocus === 'first') {
|
|
@@ -408,17 +403,32 @@ export function useSelectableCollection(options) {
|
|
|
408
403
|
if (focusedKey == null && !shouldUseVirtualFocus) {
|
|
409
404
|
focusSafely(ref.current);
|
|
410
405
|
}
|
|
411
|
-
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
autoFocusRef.current = false; // eslint-disable-next-line react-hooks/exhaustive-deps
|
|
409
|
+
}, []); // If not virtualized, scroll the focused element into view when the focusedKey changes.
|
|
410
|
+
// When virtualized, Virtualizer handles this internally.
|
|
412
411
|
|
|
413
|
-
|
|
412
|
+
useEffect(() => {
|
|
413
|
+
if (!isVirtualized && manager.focusedKey && scrollRef != null && scrollRef.current) {
|
|
414
|
+
let element = scrollRef.current.querySelector("[data-key=\"" + manager.focusedKey + "\"]");
|
|
415
|
+
|
|
416
|
+
if (element) {
|
|
417
|
+
$a9b9aa71af07c56ab1d89ca45381f4b$var$scrollIntoView(scrollRef.current, element);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}, [isVirtualized, scrollRef, manager.focusedKey]);
|
|
414
421
|
let handlers = {
|
|
415
422
|
onKeyDown,
|
|
416
423
|
onFocus,
|
|
417
424
|
onBlur,
|
|
418
425
|
|
|
419
426
|
onMouseDown(e) {
|
|
420
|
-
//
|
|
421
|
-
e.
|
|
427
|
+
// Ignore events that bubbled through portals.
|
|
428
|
+
if (e.currentTarget.contains(e.target)) {
|
|
429
|
+
// Prevent focus going to the collection when clicking on the scrollbar.
|
|
430
|
+
e.preventDefault();
|
|
431
|
+
}
|
|
422
432
|
}
|
|
423
433
|
|
|
424
434
|
};
|
|
@@ -449,6 +459,66 @@ export function useSelectableCollection(options) {
|
|
|
449
459
|
})
|
|
450
460
|
};
|
|
451
461
|
}
|
|
462
|
+
/**
|
|
463
|
+
* Scrolls `scrollView` so that `element` is visible.
|
|
464
|
+
* Similar to `element.scrollIntoView({block: 'nearest'})` (not supported in Edge),
|
|
465
|
+
* but doesn't affect parents above `scrollView`.
|
|
466
|
+
*/
|
|
467
|
+
|
|
468
|
+
function $a9b9aa71af07c56ab1d89ca45381f4b$var$scrollIntoView(scrollView, element) {
|
|
469
|
+
let offsetX = $a9b9aa71af07c56ab1d89ca45381f4b$var$relativeOffset(scrollView, element, 'left');
|
|
470
|
+
let offsetY = $a9b9aa71af07c56ab1d89ca45381f4b$var$relativeOffset(scrollView, element, 'top');
|
|
471
|
+
let width = element.offsetWidth;
|
|
472
|
+
let height = element.offsetHeight;
|
|
473
|
+
let x = scrollView.scrollLeft;
|
|
474
|
+
let y = scrollView.scrollTop;
|
|
475
|
+
let maxX = x + scrollView.offsetWidth;
|
|
476
|
+
let maxY = y + scrollView.offsetHeight;
|
|
477
|
+
|
|
478
|
+
if (offsetX <= x) {
|
|
479
|
+
x = offsetX;
|
|
480
|
+
} else if (offsetX + width > maxX) {
|
|
481
|
+
x += offsetX + width - maxX;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
if (offsetY <= y) {
|
|
485
|
+
y = offsetY;
|
|
486
|
+
} else if (offsetY + height > maxY) {
|
|
487
|
+
y += offsetY + height - maxY;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
scrollView.scrollLeft = x;
|
|
491
|
+
scrollView.scrollTop = y;
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* Computes the offset left or top from child to ancestor by accumulating
|
|
495
|
+
* offsetLeft or offsetTop through intervening offsetParents.
|
|
496
|
+
*/
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
function $a9b9aa71af07c56ab1d89ca45381f4b$var$relativeOffset(ancestor, child, axis) {
|
|
500
|
+
const prop = axis === 'left' ? 'offsetLeft' : 'offsetTop';
|
|
501
|
+
let sum = 0;
|
|
502
|
+
|
|
503
|
+
while (child.offsetParent) {
|
|
504
|
+
sum += child[prop];
|
|
505
|
+
|
|
506
|
+
if (child.offsetParent === ancestor) {
|
|
507
|
+
// Stop once we have found the ancestor we are interested in.
|
|
508
|
+
break;
|
|
509
|
+
} else if (child.offsetParent.contains(ancestor)) {
|
|
510
|
+
// If the ancestor is not `position:relative`, then we stop at
|
|
511
|
+
// _its_ offset parent, and we subtract off _its_ offset, so that
|
|
512
|
+
// we end up with the proper offset from child to ancestor.
|
|
513
|
+
sum -= ancestor[prop];
|
|
514
|
+
break;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
child = child.offsetParent;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
return sum;
|
|
521
|
+
}
|
|
452
522
|
|
|
453
523
|
/**
|
|
454
524
|
* Handles interactions with an item in a selectable collection.
|
|
@@ -461,10 +531,35 @@ export function useSelectableItem(options) {
|
|
|
461
531
|
shouldSelectOnPressUp,
|
|
462
532
|
isVirtualized,
|
|
463
533
|
shouldUseVirtualFocus,
|
|
464
|
-
focus
|
|
534
|
+
focus,
|
|
535
|
+
isDisabled,
|
|
536
|
+
onAction
|
|
465
537
|
} = options;
|
|
466
538
|
|
|
467
|
-
let onSelect = e =>
|
|
539
|
+
let onSelect = e => {
|
|
540
|
+
if (e.pointerType === 'keyboard' && $d9657c365c2f735bcaf048eee8599a4a$export$isNonContiguousSelectionModifier(e)) {
|
|
541
|
+
manager.toggleSelection(key);
|
|
542
|
+
} else {
|
|
543
|
+
if (manager.selectionMode === 'none') {
|
|
544
|
+
return;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
if (manager.selectionMode === 'single') {
|
|
548
|
+
if (manager.isSelected(key) && !manager.disallowEmptySelection) {
|
|
549
|
+
manager.toggleSelection(key);
|
|
550
|
+
} else {
|
|
551
|
+
manager.replaceSelection(key);
|
|
552
|
+
}
|
|
553
|
+
} else if (e && e.shiftKey) {
|
|
554
|
+
manager.extendSelection(key);
|
|
555
|
+
} else if (manager.selectionBehavior === 'toggle' || e && ($d9657c365c2f735bcaf048eee8599a4a$export$isCtrlKeyPressed(e) || e.pointerType === 'touch' || e.pointerType === 'virtual')) {
|
|
556
|
+
// if touch or virtual (VO) then we just want to toggle, otherwise it's impossible to multi select because they don't have modifier keys
|
|
557
|
+
manager.toggleSelection(key);
|
|
558
|
+
} else {
|
|
559
|
+
manager.replaceSelection(key);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
}; // Focus the associated DOM node when this item becomes the focusedKey
|
|
468
563
|
|
|
469
564
|
|
|
470
565
|
let isFocused = key === manager.focusedKey;
|
|
@@ -493,7 +588,12 @@ export function useSelectableItem(options) {
|
|
|
493
588
|
}
|
|
494
589
|
|
|
495
590
|
};
|
|
496
|
-
}
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
let modality = useRef(null);
|
|
594
|
+
let hasPrimaryAction = onAction && manager.selectionMode === 'none';
|
|
595
|
+
let hasSecondaryAction = onAction && manager.selectionMode !== 'none' && manager.selectionBehavior === 'replace';
|
|
596
|
+
let allowsSelection = !isDisabled && manager.canSelectItem(key); // By default, selection occurs on pointer down. This can be strange if selecting an
|
|
497
597
|
// item causes the UI to disappear immediately (e.g. menus).
|
|
498
598
|
// If shouldSelectOnPressUp is true, we use onPressUp instead of onPressStart.
|
|
499
599
|
// onPress requires a pointer down event on the same element as pointer up. For menus,
|
|
@@ -501,30 +601,43 @@ export function useSelectableItem(options) {
|
|
|
501
601
|
// the pointer up on the menu item rather than requiring a separate press.
|
|
502
602
|
// For keyboard events, selection still occurs on key down.
|
|
503
603
|
|
|
604
|
+
let itemPressProps = {};
|
|
504
605
|
|
|
505
606
|
if (shouldSelectOnPressUp) {
|
|
506
|
-
|
|
607
|
+
itemPressProps.onPressStart = e => {
|
|
608
|
+
modality.current = e.pointerType;
|
|
609
|
+
|
|
507
610
|
if (e.pointerType === 'keyboard') {
|
|
508
611
|
onSelect(e);
|
|
509
612
|
}
|
|
510
613
|
};
|
|
511
614
|
|
|
512
|
-
|
|
615
|
+
itemPressProps.onPressUp = e => {
|
|
513
616
|
if (e.pointerType !== 'keyboard') {
|
|
514
617
|
onSelect(e);
|
|
515
618
|
}
|
|
516
619
|
};
|
|
620
|
+
|
|
621
|
+
itemPressProps.onPress = hasPrimaryAction ? () => onAction() : null;
|
|
517
622
|
} else {
|
|
518
623
|
// On touch, it feels strange to select on touch down, so we special case this.
|
|
519
|
-
|
|
520
|
-
|
|
624
|
+
itemPressProps.onPressStart = e => {
|
|
625
|
+
modality.current = e.pointerType;
|
|
626
|
+
|
|
627
|
+
if (e.pointerType !== 'touch' && e.pointerType !== 'virtual') {
|
|
521
628
|
onSelect(e);
|
|
522
629
|
}
|
|
523
630
|
};
|
|
524
631
|
|
|
525
|
-
|
|
526
|
-
if (e.pointerType === 'touch') {
|
|
527
|
-
|
|
632
|
+
itemPressProps.onPress = e => {
|
|
633
|
+
if (e.pointerType === 'touch' || e.pointerType === 'virtual' || hasPrimaryAction) {
|
|
634
|
+
// Single tap on touch with selectionBehavior = 'replace' performs an action, i.e. navigation.
|
|
635
|
+
// Also perform action on press up when selectionMode = 'none'.
|
|
636
|
+
if (hasPrimaryAction || hasSecondaryAction) {
|
|
637
|
+
onAction();
|
|
638
|
+
} else {
|
|
639
|
+
onSelect(e);
|
|
640
|
+
}
|
|
528
641
|
}
|
|
529
642
|
};
|
|
530
643
|
}
|
|
@@ -533,8 +646,48 @@ export function useSelectableItem(options) {
|
|
|
533
646
|
itemProps['data-key'] = key;
|
|
534
647
|
}
|
|
535
648
|
|
|
649
|
+
itemPressProps.preventFocusOnPress = shouldUseVirtualFocus;
|
|
650
|
+
let {
|
|
651
|
+
pressProps,
|
|
652
|
+
isPressed
|
|
653
|
+
} = usePress(itemPressProps); // Double clicking with a mouse with selectionBehavior = 'replace' performs an action.
|
|
654
|
+
|
|
655
|
+
let onDoubleClick = hasSecondaryAction ? e => {
|
|
656
|
+
if (modality.current === 'mouse') {
|
|
657
|
+
e.stopPropagation();
|
|
658
|
+
e.preventDefault();
|
|
659
|
+
onAction();
|
|
660
|
+
}
|
|
661
|
+
} : undefined; // Long pressing an item with touch when selectionBehavior = 'replace' switches the selection behavior
|
|
662
|
+
// to 'toggle'. This changes the single tap behavior from performing an action (i.e. navigating) to
|
|
663
|
+
// selecting, and may toggle the appearance of a UI affordance like checkboxes on each item.
|
|
664
|
+
// TODO: what about when drag and drop is also enabled??
|
|
665
|
+
|
|
666
|
+
let {
|
|
667
|
+
longPressProps
|
|
668
|
+
} = useLongPress({
|
|
669
|
+
isDisabled: !hasSecondaryAction,
|
|
670
|
+
|
|
671
|
+
onLongPress(e) {
|
|
672
|
+
if (e.pointerType === 'touch') {
|
|
673
|
+
onSelect(e);
|
|
674
|
+
manager.setSelectionBehavior('toggle');
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
}); // Pressing the Enter key with selectionBehavior = 'replace' performs an action (i.e. navigation).
|
|
679
|
+
|
|
680
|
+
let onKeyUp = hasSecondaryAction ? e => {
|
|
681
|
+
if (e.key === 'Enter') {
|
|
682
|
+
onAction();
|
|
683
|
+
}
|
|
684
|
+
} : undefined;
|
|
536
685
|
return {
|
|
537
|
-
itemProps
|
|
686
|
+
itemProps: mergeProps(itemProps, allowsSelection || hasPrimaryAction ? pressProps : {}, hasSecondaryAction ? longPressProps : {}, {
|
|
687
|
+
onKeyUp,
|
|
688
|
+
onDoubleClick
|
|
689
|
+
}),
|
|
690
|
+
isPressed
|
|
538
691
|
};
|
|
539
692
|
}
|
|
540
693
|
|
|
@@ -706,18 +859,7 @@ export function useSelectableList(props) {
|
|
|
706
859
|
usage: 'search',
|
|
707
860
|
sensitivity: 'base'
|
|
708
861
|
});
|
|
709
|
-
let delegate = useMemo(() => keyboardDelegate || new ListKeyboardDelegate(collection, disabledKeys, ref, collator), [keyboardDelegate, collection, disabledKeys, ref, collator]);
|
|
710
|
-
// When virtualized, Virtualizer handles this internally.
|
|
711
|
-
|
|
712
|
-
useEffect(() => {
|
|
713
|
-
if (!isVirtualized && selectionManager.focusedKey && (ref == null ? void 0 : ref.current)) {
|
|
714
|
-
let element = ref.current.querySelector("[data-key=\"" + selectionManager.focusedKey + "\"]");
|
|
715
|
-
|
|
716
|
-
if (element) {
|
|
717
|
-
$a09ba753e08b703267f2392f7fc8e96$var$scrollIntoView(ref.current, element);
|
|
718
|
-
}
|
|
719
|
-
}
|
|
720
|
-
}, [isVirtualized, ref, selectionManager.focusedKey]);
|
|
862
|
+
let delegate = useMemo(() => keyboardDelegate || new ListKeyboardDelegate(collection, disabledKeys, ref, collator), [keyboardDelegate, collection, disabledKeys, ref, collator]);
|
|
721
863
|
let {
|
|
722
864
|
collectionProps
|
|
723
865
|
} = useSelectableCollection({
|
|
@@ -730,41 +872,12 @@ export function useSelectableList(props) {
|
|
|
730
872
|
selectOnFocus,
|
|
731
873
|
disallowTypeAhead,
|
|
732
874
|
shouldUseVirtualFocus,
|
|
733
|
-
allowsTabNavigation
|
|
875
|
+
allowsTabNavigation,
|
|
876
|
+
isVirtualized,
|
|
877
|
+
scrollRef: ref
|
|
734
878
|
});
|
|
735
879
|
return {
|
|
736
880
|
listProps: collectionProps
|
|
737
881
|
};
|
|
738
882
|
}
|
|
739
|
-
/**
|
|
740
|
-
* Scrolls `scrollView` so that `element` is visible.
|
|
741
|
-
* Similar to `element.scrollIntoView({block: 'nearest'})` (not supported in Edge),
|
|
742
|
-
* but doesn't affect parents above `scrollView`.
|
|
743
|
-
*/
|
|
744
|
-
|
|
745
|
-
function $a09ba753e08b703267f2392f7fc8e96$var$scrollIntoView(scrollView, element) {
|
|
746
|
-
let offsetX = element.offsetLeft - scrollView.offsetLeft;
|
|
747
|
-
let offsetY = element.offsetTop - scrollView.offsetTop;
|
|
748
|
-
let width = element.offsetWidth;
|
|
749
|
-
let height = element.offsetHeight;
|
|
750
|
-
let x = scrollView.scrollLeft;
|
|
751
|
-
let y = scrollView.scrollTop;
|
|
752
|
-
let maxX = x + scrollView.offsetWidth;
|
|
753
|
-
let maxY = y + scrollView.offsetHeight;
|
|
754
|
-
|
|
755
|
-
if (offsetX <= x) {
|
|
756
|
-
x = offsetX;
|
|
757
|
-
} else if (offsetX + width > maxX) {
|
|
758
|
-
x += offsetX + width - maxX;
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
if (offsetY <= y) {
|
|
762
|
-
y = offsetY;
|
|
763
|
-
} else if (offsetY + height > maxY) {
|
|
764
|
-
y += offsetY + height - maxY;
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
scrollView.scrollLeft = x;
|
|
768
|
-
scrollView.scrollTop = y;
|
|
769
|
-
}
|
|
770
883
|
//# sourceMappingURL=module.js.map
|