@react-aria/selection 3.25.1 → 3.27.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/DOMLayoutDelegate.main.js +5 -5
- package/dist/DOMLayoutDelegate.main.js.map +1 -1
- package/dist/DOMLayoutDelegate.mjs +5 -5
- package/dist/DOMLayoutDelegate.module.js +5 -5
- package/dist/DOMLayoutDelegate.module.js.map +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/useSelectableCollection.main.js +30 -31
- package/dist/useSelectableCollection.main.js.map +1 -1
- package/dist/useSelectableCollection.mjs +31 -32
- package/dist/useSelectableCollection.module.js +31 -32
- package/dist/useSelectableCollection.module.js.map +1 -1
- package/dist/useSelectableItem.main.js +9 -2
- package/dist/useSelectableItem.main.js.map +1 -1
- package/dist/useSelectableItem.mjs +9 -2
- package/dist/useSelectableItem.module.js +9 -2
- package/dist/useSelectableItem.module.js.map +1 -1
- package/package.json +8 -8
- package/src/DOMLayoutDelegate.ts +4 -4
- package/src/useSelectableCollection.ts +30 -34
- package/src/useSelectableItem.ts +3 -1
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import {CLEAR_FOCUS_EVENT, FOCUS_EVENT, focusWithoutScrolling, getActiveElement, isCtrlKeyPressed, mergeProps, scrollIntoView, scrollIntoViewport,
|
|
13
|
+
import {CLEAR_FOCUS_EVENT, FOCUS_EVENT, focusWithoutScrolling, getActiveElement, isCtrlKeyPressed, isTabbable, mergeProps, scrollIntoView, scrollIntoViewport, useEvent, useRouter, useUpdateLayoutEffect} from '@react-aria/utils';
|
|
14
14
|
import {dispatchVirtualFocus, getFocusableTreeWalker, moveVirtualFocus} from '@react-aria/focus';
|
|
15
15
|
import {DOMAttributes, FocusableElement, FocusStrategy, Key, KeyboardDelegate, RefObject} from '@react-types/shared';
|
|
16
16
|
import {flushSync} from 'react-dom';
|
|
@@ -312,7 +312,10 @@ export function useSelectableCollection(options: AriaSelectableCollectionOptions
|
|
|
312
312
|
}
|
|
313
313
|
} while (last);
|
|
314
314
|
|
|
315
|
-
|
|
315
|
+
// If the active element is NOT tabbable but is contained by an element that IS tabbable (aka the cell), the browser will actually move focus to
|
|
316
|
+
// the containing element. We need to special case this so that tab will move focus out of the grid instead of looping between
|
|
317
|
+
// focusing the containing cell and back to the non-tabbable child element
|
|
318
|
+
if (next && (!next.contains(document.activeElement) || (document.activeElement && !isTabbable(document.activeElement)))) {
|
|
316
319
|
focusWithoutScrolling(next);
|
|
317
320
|
}
|
|
318
321
|
}
|
|
@@ -413,49 +416,42 @@ export function useSelectableCollection(options: AriaSelectableCollectionOptions
|
|
|
413
416
|
}
|
|
414
417
|
});
|
|
415
418
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
419
|
+
// update active descendant
|
|
420
|
+
useUpdateLayoutEffect(() => {
|
|
421
|
+
if (shouldVirtualFocusFirst.current) {
|
|
422
|
+
let keyToFocus = delegate.getFirstKey?.() ?? null;
|
|
423
|
+
|
|
424
|
+
// If no focusable items exist in the list, make sure to clear any activedescendant that may still exist and move focus back to
|
|
425
|
+
// the original active element (e.g. the autocomplete input)
|
|
426
|
+
if (keyToFocus == null) {
|
|
427
|
+
let previousActiveElement = getActiveElement();
|
|
428
|
+
moveVirtualFocus(ref.current);
|
|
429
|
+
dispatchVirtualFocus(previousActiveElement!, null);
|
|
430
|
+
|
|
431
|
+
// If there wasn't a focusable key but the collection had items, then that means we aren't in an intermediate load state and all keys are disabled.
|
|
432
|
+
// Reset shouldVirtualFocusFirst so that we don't erronously autofocus an item when the collection is filtered again.
|
|
433
|
+
if (manager.collection.size > 0) {
|
|
434
|
+
shouldVirtualFocusFirst.current = false;
|
|
435
|
+
}
|
|
436
|
+
} else {
|
|
437
|
+
manager.setFocusedKey(keyToFocus);
|
|
438
|
+
// Only set shouldVirtualFocusFirst to false if we've successfully set the first key as the focused key
|
|
439
|
+
// If there wasn't a key to focus, we might be in a temporary loading state so we'll want to still focus the first key
|
|
440
|
+
// after the collection updates after load
|
|
429
441
|
shouldVirtualFocusFirst.current = false;
|
|
430
442
|
}
|
|
431
|
-
} else {
|
|
432
|
-
manager.setFocusedKey(keyToFocus);
|
|
433
|
-
// Only set shouldVirtualFocusFirst to false if we've successfully set the first key as the focused key
|
|
434
|
-
// If there wasn't a key to focus, we might be in a temporary loading state so we'll want to still focus the first key
|
|
435
|
-
// after the collection updates after load
|
|
436
|
-
shouldVirtualFocusFirst.current = false;
|
|
437
443
|
}
|
|
438
|
-
});
|
|
444
|
+
}, [manager.collection]);
|
|
439
445
|
|
|
446
|
+
// reset focus first flag
|
|
440
447
|
useUpdateLayoutEffect(() => {
|
|
441
|
-
if (shouldVirtualFocusFirst.current) {
|
|
442
|
-
updateActiveDescendant();
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
}, [manager.collection, updateActiveDescendant]);
|
|
446
|
-
|
|
447
|
-
let resetFocusFirstFlag = useEffectEvent(() => {
|
|
448
448
|
// If user causes the focused key to change in any other way, clear shouldVirtualFocusFirst so we don't
|
|
449
449
|
// accidentally move focus from under them. Skip this if the collection was empty because we might be in a load
|
|
450
450
|
// state and will still want to focus the first item after load
|
|
451
451
|
if (manager.collection.size > 0) {
|
|
452
452
|
shouldVirtualFocusFirst.current = false;
|
|
453
453
|
}
|
|
454
|
-
});
|
|
455
|
-
|
|
456
|
-
useUpdateLayoutEffect(() => {
|
|
457
|
-
resetFocusFirstFlag();
|
|
458
|
-
}, [manager.focusedKey, resetFocusFirstFlag]);
|
|
454
|
+
}, [manager.focusedKey]);
|
|
459
455
|
|
|
460
456
|
useEvent(ref, CLEAR_FOCUS_EVENT, !shouldUseVirtualFocus ? undefined : (e: any) => {
|
|
461
457
|
e.stopPropagation();
|
package/src/useSelectableItem.ts
CHANGED
|
@@ -205,8 +205,9 @@ export function useSelectableItem(options: SelectableItemOptions): SelectableIte
|
|
|
205
205
|
// With highlight selection, onAction is secondary, and occurs on double click. Single click selects the row.
|
|
206
206
|
// With touch, onAction occurs on single tap, and long press enters selection mode.
|
|
207
207
|
let isLinkOverride = manager.isLink(key) && linkBehavior === 'override';
|
|
208
|
+
let isActionOverride = onAction && options['UNSTABLE_itemBehavior'] === 'action';
|
|
208
209
|
let hasLinkAction = manager.isLink(key) && linkBehavior !== 'selection' && linkBehavior !== 'none';
|
|
209
|
-
let allowsSelection = !isDisabled && manager.canSelectItem(key) && !isLinkOverride;
|
|
210
|
+
let allowsSelection = !isDisabled && manager.canSelectItem(key) && !isLinkOverride && !isActionOverride;
|
|
210
211
|
let allowsActions = (onAction || hasLinkAction) && !isDisabled;
|
|
211
212
|
let hasPrimaryAction = allowsActions && (
|
|
212
213
|
manager.selectionBehavior === 'replace'
|
|
@@ -225,6 +226,7 @@ export function useSelectableItem(options: SelectableItemOptions): SelectableIte
|
|
|
225
226
|
let performAction = (e) => {
|
|
226
227
|
if (onAction) {
|
|
227
228
|
onAction();
|
|
229
|
+
ref.current?.dispatchEvent(new CustomEvent('react-aria-item-action', {bubbles: true}));
|
|
228
230
|
}
|
|
229
231
|
|
|
230
232
|
if (hasLinkAction && ref.current) {
|