@react-aria/selection
Advanced tools
Comparing version 3.0.0-nightly-7eae25e12-241205 to 3.0.0-nightly-801ef48a8-250207
@@ -1,2 +0,2 @@ | ||
import { DOMAttributes, Key, KeyboardDelegate, FocusStrategy, RefObject, FocusableElement, LayoutDelegate, Rect, Size, Collection, Direction, DisabledBehavior, Node, Orientation } from "@react-types/shared"; | ||
import { DOMAttributes, Key, KeyboardDelegate, FocusStrategy, RefObject, DOMProps, FocusableElement, LayoutDelegate, Rect, Size, Collection, Direction, DisabledBehavior, Node, Orientation } from "@react-types/shared"; | ||
import { MultipleSelectionManager } from "@react-stately/selection"; | ||
@@ -104,3 +104,3 @@ export interface AriaTypeSelectOptions { | ||
export function useSelectableCollection(options: AriaSelectableCollectionOptions): SelectableCollectionAria; | ||
export interface SelectableItemOptions { | ||
export interface SelectableItemOptions extends DOMProps { | ||
/** | ||
@@ -107,0 +107,0 @@ * An interface for reading and updating multiple selection state. |
var $ee0bdf4faa47f2a8$exports = require("./utils.main.js"); | ||
var $a1189052f36475e8$exports = require("./useTypeSelect.main.js"); | ||
var $bT8Bh$reactariautils = require("@react-aria/utils"); | ||
var $bT8Bh$reactdom = require("react-dom"); | ||
var $bT8Bh$react = require("react"); | ||
var $bT8Bh$reactariafocus = require("@react-aria/focus"); | ||
var $bT8Bh$reactariautils = require("@react-aria/utils"); | ||
var $bT8Bh$reactariainteractions = require("@react-aria/interactions"); | ||
@@ -114,6 +114,6 @@ var $bT8Bh$reactariai18n = require("@react-aria/i18n"); | ||
e.preventDefault(); | ||
let firstKey = delegate.getFirstKey(manager.focusedKey, (0, $ee0bdf4faa47f2a8$exports.isCtrlKeyPressed)(e)); | ||
let firstKey = delegate.getFirstKey(manager.focusedKey, (0, $bT8Bh$reactariautils.isCtrlKeyPressed)(e)); | ||
manager.setFocusedKey(firstKey); | ||
if (firstKey != null) { | ||
if ((0, $ee0bdf4faa47f2a8$exports.isCtrlKeyPressed)(e) && e.shiftKey && manager.selectionMode === 'multiple') manager.extendSelection(firstKey); | ||
if ((0, $bT8Bh$reactariautils.isCtrlKeyPressed)(e) && e.shiftKey && manager.selectionMode === 'multiple') manager.extendSelection(firstKey); | ||
else if (selectOnFocus) manager.replaceSelection(firstKey); | ||
@@ -127,6 +127,6 @@ } | ||
e.preventDefault(); | ||
let lastKey = delegate.getLastKey(manager.focusedKey, (0, $ee0bdf4faa47f2a8$exports.isCtrlKeyPressed)(e)); | ||
let lastKey = delegate.getLastKey(manager.focusedKey, (0, $bT8Bh$reactariautils.isCtrlKeyPressed)(e)); | ||
manager.setFocusedKey(lastKey); | ||
if (lastKey != null) { | ||
if ((0, $ee0bdf4faa47f2a8$exports.isCtrlKeyPressed)(e) && e.shiftKey && manager.selectionMode === 'multiple') manager.extendSelection(lastKey); | ||
if ((0, $bT8Bh$reactariautils.isCtrlKeyPressed)(e) && e.shiftKey && manager.selectionMode === 'multiple') manager.extendSelection(lastKey); | ||
else if (selectOnFocus) manager.replaceSelection(lastKey); | ||
@@ -155,3 +155,3 @@ } | ||
case 'a': | ||
if ((0, $ee0bdf4faa47f2a8$exports.isCtrlKeyPressed)(e) && manager.selectionMode === 'multiple' && disallowSelectAll !== true) { | ||
if ((0, $bT8Bh$reactariautils.isCtrlKeyPressed)(e) && manager.selectionMode === 'multiple' && disallowSelectAll !== true) { | ||
e.preventDefault(); | ||
@@ -218,6 +218,6 @@ manager.selectAll(); | ||
var _delegate_getLastKey, _delegate_getFirstKey; | ||
let navigateToFirstKey = (key)=>{ | ||
let navigateToKey = (key)=>{ | ||
if (key != null) { | ||
manager.setFocusedKey(key); | ||
if (selectOnFocus) manager.replaceSelection(key); | ||
if (selectOnFocus && !manager.isSelected(key)) manager.replaceSelection(key); | ||
} | ||
@@ -230,4 +230,4 @@ }; | ||
var _manager_lastSelectedKey, _manager_firstSelectedKey; | ||
if (relatedTarget && e.currentTarget.compareDocumentPosition(relatedTarget) & Node.DOCUMENT_POSITION_FOLLOWING) navigateToFirstKey((_manager_lastSelectedKey = manager.lastSelectedKey) !== null && _manager_lastSelectedKey !== void 0 ? _manager_lastSelectedKey : (_delegate_getLastKey = delegate.getLastKey) === null || _delegate_getLastKey === void 0 ? void 0 : _delegate_getLastKey.call(delegate)); | ||
else navigateToFirstKey((_manager_firstSelectedKey = manager.firstSelectedKey) !== null && _manager_firstSelectedKey !== void 0 ? _manager_firstSelectedKey : (_delegate_getFirstKey = delegate.getFirstKey) === null || _delegate_getFirstKey === void 0 ? void 0 : _delegate_getFirstKey.call(delegate)); | ||
if (relatedTarget && e.currentTarget.compareDocumentPosition(relatedTarget) & Node.DOCUMENT_POSITION_FOLLOWING) navigateToKey((_manager_lastSelectedKey = manager.lastSelectedKey) !== null && _manager_lastSelectedKey !== void 0 ? _manager_lastSelectedKey : (_delegate_getLastKey = delegate.getLastKey) === null || _delegate_getLastKey === void 0 ? void 0 : _delegate_getLastKey.call(delegate)); | ||
else navigateToKey((_manager_firstSelectedKey = manager.firstSelectedKey) !== null && _manager_firstSelectedKey !== void 0 ? _manager_firstSelectedKey : (_delegate_getFirstKey = delegate.getFirstKey) === null || _delegate_getFirstKey === void 0 ? void 0 : _delegate_getFirstKey.call(delegate)); | ||
} else if (!isVirtualized && scrollRef.current) { | ||
@@ -255,2 +255,61 @@ // Restore the scroll position to what it was before. | ||
}; | ||
// Ref to track whether the first item in the collection should be automatically focused. Specifically used for autocomplete when user types | ||
// to focus the first key AFTER the collection updates. | ||
// TODO: potentially expand the usage of this | ||
let shouldVirtualFocusFirst = (0, $bT8Bh$react.useRef)(false); | ||
// Add event listeners for custom virtual events. These handle updating the focused key in response to various keyboard events | ||
// at the autocomplete level | ||
// TODO: fix type later | ||
(0, $bT8Bh$reactariautils.useEvent)(ref, (0, $bT8Bh$reactariautils.FOCUS_EVENT), !shouldUseVirtualFocus ? undefined : (e)=>{ | ||
let { detail: detail } = e; | ||
e.stopPropagation(); | ||
manager.setFocused(true); | ||
// If the user is typing forwards, autofocus the first option in the list. | ||
if ((detail === null || detail === void 0 ? void 0 : detail.focusStrategy) === 'first') shouldVirtualFocusFirst.current = true; | ||
}); | ||
let updateActiveDescendant = (0, $bT8Bh$reactariautils.useEffectEvent)(()=>{ | ||
var _delegate_getFirstKey; | ||
var _delegate_getFirstKey1; | ||
let keyToFocus = (_delegate_getFirstKey1 = (_delegate_getFirstKey = delegate.getFirstKey) === null || _delegate_getFirstKey === void 0 ? void 0 : _delegate_getFirstKey.call(delegate)) !== null && _delegate_getFirstKey1 !== void 0 ? _delegate_getFirstKey1 : null; | ||
// If no focusable items exist in the list, make sure to clear any activedescendant that may still exist | ||
if (keyToFocus == null) { | ||
var _ref_current; | ||
(_ref_current = ref.current) === null || _ref_current === void 0 ? void 0 : _ref_current.dispatchEvent(new CustomEvent((0, $bT8Bh$reactariautils.UPDATE_ACTIVEDESCENDANT), { | ||
cancelable: true, | ||
bubbles: true | ||
})); | ||
// 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. | ||
// Reset shouldVirtualFocusFirst so that we don't erronously autofocus an item when the collection is filtered again. | ||
if (manager.collection.size > 0) shouldVirtualFocusFirst.current = false; | ||
} else { | ||
manager.setFocusedKey(keyToFocus); | ||
// Only set shouldVirtualFocusFirst to false if we've successfully set the first key as the focused key | ||
// 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 | ||
// after the collection updates after load | ||
shouldVirtualFocusFirst.current = false; | ||
} | ||
}); | ||
(0, $bT8Bh$reactariautils.useUpdateLayoutEffect)(()=>{ | ||
if (shouldVirtualFocusFirst.current) updateActiveDescendant(); | ||
}, [ | ||
manager.collection, | ||
updateActiveDescendant | ||
]); | ||
let resetFocusFirstFlag = (0, $bT8Bh$reactariautils.useEffectEvent)(()=>{ | ||
// If user causes the focused key to change in any other way, clear shouldVirtualFocusFirst so we don't | ||
// accidentally move focus from under them. Skip this if the collection was empty because we might be in a load | ||
// state and will still want to focus the first item after load | ||
if (manager.collection.size > 0) shouldVirtualFocusFirst.current = false; | ||
}); | ||
(0, $bT8Bh$reactariautils.useUpdateLayoutEffect)(()=>{ | ||
resetFocusFirstFlag(); | ||
}, [ | ||
manager.focusedKey, | ||
resetFocusFirstFlag | ||
]); | ||
(0, $bT8Bh$reactariautils.useEvent)(ref, (0, $bT8Bh$reactariautils.CLEAR_FOCUS_EVENT), !shouldUseVirtualFocus ? undefined : (e)=>{ | ||
e.stopPropagation(); | ||
manager.setFocused(false); | ||
manager.setFocusedKey(null); | ||
}); | ||
const autoFocusRef = (0, $bT8Bh$react.useRef)(autoFocus); | ||
@@ -325,6 +384,5 @@ (0, $bT8Bh$react.useEffect)(()=>{ | ||
// This will be marshalled to either the first or last item depending on where focus came from. | ||
// If using virtual focus, don't set a tabIndex at all so that VoiceOver on iOS 14 doesn't try | ||
// to move real DOM focus to the element anyway. | ||
let tabIndex = undefined; | ||
if (!shouldUseVirtualFocus) tabIndex = manager.focusedKey == null ? 0 : -1; | ||
else tabIndex = -1; | ||
return { | ||
@@ -331,0 +389,0 @@ collectionProps: { |
@@ -1,7 +0,7 @@ | ||
import {isCtrlKeyPressed as $feb5ffebff200149$export$16792effe837dba3, isNonContiguousSelectionModifier as $feb5ffebff200149$export$d3e3bd3e26688c04} from "./utils.module.js"; | ||
import {isNonContiguousSelectionModifier as $feb5ffebff200149$export$d3e3bd3e26688c04} from "./utils.module.js"; | ||
import {useTypeSelect as $fb3050f43d946246$export$e32c88dfddc6e1d8} from "./useTypeSelect.module.js"; | ||
import {useRouter as $3H3GQ$useRouter, isCtrlKeyPressed as $3H3GQ$isCtrlKeyPressed, focusWithoutScrolling as $3H3GQ$focusWithoutScrolling, useEvent as $3H3GQ$useEvent, scrollIntoViewport as $3H3GQ$scrollIntoViewport, FOCUS_EVENT as $3H3GQ$FOCUS_EVENT, useEffectEvent as $3H3GQ$useEffectEvent, UPDATE_ACTIVEDESCENDANT as $3H3GQ$UPDATE_ACTIVEDESCENDANT, useUpdateLayoutEffect as $3H3GQ$useUpdateLayoutEffect, CLEAR_FOCUS_EVENT as $3H3GQ$CLEAR_FOCUS_EVENT, scrollIntoView as $3H3GQ$scrollIntoView, mergeProps as $3H3GQ$mergeProps} from "@react-aria/utils"; | ||
import {flushSync as $3H3GQ$flushSync} from "react-dom"; | ||
import {useRef as $3H3GQ$useRef, useEffect as $3H3GQ$useEffect} from "react"; | ||
import {getFocusableTreeWalker as $3H3GQ$getFocusableTreeWalker, focusSafely as $3H3GQ$focusSafely} from "@react-aria/focus"; | ||
import {useRouter as $3H3GQ$useRouter, focusWithoutScrolling as $3H3GQ$focusWithoutScrolling, useEvent as $3H3GQ$useEvent, scrollIntoViewport as $3H3GQ$scrollIntoViewport, scrollIntoView as $3H3GQ$scrollIntoView, mergeProps as $3H3GQ$mergeProps} from "@react-aria/utils"; | ||
import {getInteractionModality as $3H3GQ$getInteractionModality} from "@react-aria/interactions"; | ||
@@ -108,6 +108,6 @@ import {useLocale as $3H3GQ$useLocale} from "@react-aria/i18n"; | ||
e.preventDefault(); | ||
let firstKey = delegate.getFirstKey(manager.focusedKey, (0, $feb5ffebff200149$export$16792effe837dba3)(e)); | ||
let firstKey = delegate.getFirstKey(manager.focusedKey, (0, $3H3GQ$isCtrlKeyPressed)(e)); | ||
manager.setFocusedKey(firstKey); | ||
if (firstKey != null) { | ||
if ((0, $feb5ffebff200149$export$16792effe837dba3)(e) && e.shiftKey && manager.selectionMode === 'multiple') manager.extendSelection(firstKey); | ||
if ((0, $3H3GQ$isCtrlKeyPressed)(e) && e.shiftKey && manager.selectionMode === 'multiple') manager.extendSelection(firstKey); | ||
else if (selectOnFocus) manager.replaceSelection(firstKey); | ||
@@ -121,6 +121,6 @@ } | ||
e.preventDefault(); | ||
let lastKey = delegate.getLastKey(manager.focusedKey, (0, $feb5ffebff200149$export$16792effe837dba3)(e)); | ||
let lastKey = delegate.getLastKey(manager.focusedKey, (0, $3H3GQ$isCtrlKeyPressed)(e)); | ||
manager.setFocusedKey(lastKey); | ||
if (lastKey != null) { | ||
if ((0, $feb5ffebff200149$export$16792effe837dba3)(e) && e.shiftKey && manager.selectionMode === 'multiple') manager.extendSelection(lastKey); | ||
if ((0, $3H3GQ$isCtrlKeyPressed)(e) && e.shiftKey && manager.selectionMode === 'multiple') manager.extendSelection(lastKey); | ||
else if (selectOnFocus) manager.replaceSelection(lastKey); | ||
@@ -149,3 +149,3 @@ } | ||
case 'a': | ||
if ((0, $feb5ffebff200149$export$16792effe837dba3)(e) && manager.selectionMode === 'multiple' && disallowSelectAll !== true) { | ||
if ((0, $3H3GQ$isCtrlKeyPressed)(e) && manager.selectionMode === 'multiple' && disallowSelectAll !== true) { | ||
e.preventDefault(); | ||
@@ -212,6 +212,6 @@ manager.selectAll(); | ||
var _delegate_getLastKey, _delegate_getFirstKey; | ||
let navigateToFirstKey = (key)=>{ | ||
let navigateToKey = (key)=>{ | ||
if (key != null) { | ||
manager.setFocusedKey(key); | ||
if (selectOnFocus) manager.replaceSelection(key); | ||
if (selectOnFocus && !manager.isSelected(key)) manager.replaceSelection(key); | ||
} | ||
@@ -224,4 +224,4 @@ }; | ||
var _manager_lastSelectedKey, _manager_firstSelectedKey; | ||
if (relatedTarget && e.currentTarget.compareDocumentPosition(relatedTarget) & Node.DOCUMENT_POSITION_FOLLOWING) navigateToFirstKey((_manager_lastSelectedKey = manager.lastSelectedKey) !== null && _manager_lastSelectedKey !== void 0 ? _manager_lastSelectedKey : (_delegate_getLastKey = delegate.getLastKey) === null || _delegate_getLastKey === void 0 ? void 0 : _delegate_getLastKey.call(delegate)); | ||
else navigateToFirstKey((_manager_firstSelectedKey = manager.firstSelectedKey) !== null && _manager_firstSelectedKey !== void 0 ? _manager_firstSelectedKey : (_delegate_getFirstKey = delegate.getFirstKey) === null || _delegate_getFirstKey === void 0 ? void 0 : _delegate_getFirstKey.call(delegate)); | ||
if (relatedTarget && e.currentTarget.compareDocumentPosition(relatedTarget) & Node.DOCUMENT_POSITION_FOLLOWING) navigateToKey((_manager_lastSelectedKey = manager.lastSelectedKey) !== null && _manager_lastSelectedKey !== void 0 ? _manager_lastSelectedKey : (_delegate_getLastKey = delegate.getLastKey) === null || _delegate_getLastKey === void 0 ? void 0 : _delegate_getLastKey.call(delegate)); | ||
else navigateToKey((_manager_firstSelectedKey = manager.firstSelectedKey) !== null && _manager_firstSelectedKey !== void 0 ? _manager_firstSelectedKey : (_delegate_getFirstKey = delegate.getFirstKey) === null || _delegate_getFirstKey === void 0 ? void 0 : _delegate_getFirstKey.call(delegate)); | ||
} else if (!isVirtualized && scrollRef.current) { | ||
@@ -249,2 +249,61 @@ // Restore the scroll position to what it was before. | ||
}; | ||
// Ref to track whether the first item in the collection should be automatically focused. Specifically used for autocomplete when user types | ||
// to focus the first key AFTER the collection updates. | ||
// TODO: potentially expand the usage of this | ||
let shouldVirtualFocusFirst = (0, $3H3GQ$useRef)(false); | ||
// Add event listeners for custom virtual events. These handle updating the focused key in response to various keyboard events | ||
// at the autocomplete level | ||
// TODO: fix type later | ||
(0, $3H3GQ$useEvent)(ref, (0, $3H3GQ$FOCUS_EVENT), !shouldUseVirtualFocus ? undefined : (e)=>{ | ||
let { detail: detail } = e; | ||
e.stopPropagation(); | ||
manager.setFocused(true); | ||
// If the user is typing forwards, autofocus the first option in the list. | ||
if ((detail === null || detail === void 0 ? void 0 : detail.focusStrategy) === 'first') shouldVirtualFocusFirst.current = true; | ||
}); | ||
let updateActiveDescendant = (0, $3H3GQ$useEffectEvent)(()=>{ | ||
var _delegate_getFirstKey; | ||
var _delegate_getFirstKey1; | ||
let keyToFocus = (_delegate_getFirstKey1 = (_delegate_getFirstKey = delegate.getFirstKey) === null || _delegate_getFirstKey === void 0 ? void 0 : _delegate_getFirstKey.call(delegate)) !== null && _delegate_getFirstKey1 !== void 0 ? _delegate_getFirstKey1 : null; | ||
// If no focusable items exist in the list, make sure to clear any activedescendant that may still exist | ||
if (keyToFocus == null) { | ||
var _ref_current; | ||
(_ref_current = ref.current) === null || _ref_current === void 0 ? void 0 : _ref_current.dispatchEvent(new CustomEvent((0, $3H3GQ$UPDATE_ACTIVEDESCENDANT), { | ||
cancelable: true, | ||
bubbles: true | ||
})); | ||
// 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. | ||
// Reset shouldVirtualFocusFirst so that we don't erronously autofocus an item when the collection is filtered again. | ||
if (manager.collection.size > 0) shouldVirtualFocusFirst.current = false; | ||
} else { | ||
manager.setFocusedKey(keyToFocus); | ||
// Only set shouldVirtualFocusFirst to false if we've successfully set the first key as the focused key | ||
// 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 | ||
// after the collection updates after load | ||
shouldVirtualFocusFirst.current = false; | ||
} | ||
}); | ||
(0, $3H3GQ$useUpdateLayoutEffect)(()=>{ | ||
if (shouldVirtualFocusFirst.current) updateActiveDescendant(); | ||
}, [ | ||
manager.collection, | ||
updateActiveDescendant | ||
]); | ||
let resetFocusFirstFlag = (0, $3H3GQ$useEffectEvent)(()=>{ | ||
// If user causes the focused key to change in any other way, clear shouldVirtualFocusFirst so we don't | ||
// accidentally move focus from under them. Skip this if the collection was empty because we might be in a load | ||
// state and will still want to focus the first item after load | ||
if (manager.collection.size > 0) shouldVirtualFocusFirst.current = false; | ||
}); | ||
(0, $3H3GQ$useUpdateLayoutEffect)(()=>{ | ||
resetFocusFirstFlag(); | ||
}, [ | ||
manager.focusedKey, | ||
resetFocusFirstFlag | ||
]); | ||
(0, $3H3GQ$useEvent)(ref, (0, $3H3GQ$CLEAR_FOCUS_EVENT), !shouldUseVirtualFocus ? undefined : (e)=>{ | ||
e.stopPropagation(); | ||
manager.setFocused(false); | ||
manager.setFocusedKey(null); | ||
}); | ||
const autoFocusRef = (0, $3H3GQ$useRef)(autoFocus); | ||
@@ -319,6 +378,5 @@ (0, $3H3GQ$useEffect)(()=>{ | ||
// This will be marshalled to either the first or last item depending on where focus came from. | ||
// If using virtual focus, don't set a tabIndex at all so that VoiceOver on iOS 14 doesn't try | ||
// to move real DOM focus to the element anyway. | ||
let tabIndex = undefined; | ||
if (!shouldUseVirtualFocus) tabIndex = manager.focusedKey == null ? 0 : -1; | ||
else tabIndex = -1; | ||
return { | ||
@@ -325,0 +383,0 @@ collectionProps: { |
@@ -29,4 +29,5 @@ var $ee0bdf4faa47f2a8$exports = require("./utils.main.js"); | ||
function $433b1145b0781e10$export$ecf600387e221c37(options) { | ||
let { selectionManager: manager, key: key, ref: ref, shouldSelectOnPressUp: shouldSelectOnPressUp, shouldUseVirtualFocus: shouldUseVirtualFocus, focus: focus, isDisabled: isDisabled, onAction: onAction, allowsDifferentPressOrigin: allowsDifferentPressOrigin, linkBehavior: linkBehavior = 'action' } = options; | ||
let { id: id, selectionManager: manager, key: key, ref: ref, shouldSelectOnPressUp: shouldSelectOnPressUp, shouldUseVirtualFocus: shouldUseVirtualFocus, focus: focus, isDisabled: isDisabled, onAction: onAction, allowsDifferentPressOrigin: allowsDifferentPressOrigin, linkBehavior: linkBehavior = 'action' } = options; | ||
let router = (0, $i4XHw$reactariautils.useRouter)(); | ||
id = (0, $i4XHw$reactariautils.useId)(id); | ||
let onSelect = (e)=>{ | ||
@@ -49,3 +50,3 @@ if (e.pointerType === 'keyboard' && (0, $ee0bdf4faa47f2a8$exports.isNonContiguousSelectionModifier)(e)) manager.toggleSelection(key); | ||
} else if (e && e.shiftKey) manager.extendSelection(key); | ||
else if (manager.selectionBehavior === 'toggle' || e && ((0, $ee0bdf4faa47f2a8$exports.isCtrlKeyPressed)(e) || e.pointerType === 'touch' || e.pointerType === 'virtual')) // 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 | ||
else if (manager.selectionBehavior === 'toggle' || e && ((0, $i4XHw$reactariautils.isCtrlKeyPressed)(e) || e.pointerType === 'touch' || e.pointerType === 'virtual')) // 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 | ||
manager.toggleSelection(key); | ||
@@ -56,7 +57,19 @@ else manager.replaceSelection(key); | ||
// Focus the associated DOM node when this item becomes the focusedKey | ||
// TODO: can't make this useLayoutEffect bacause it breaks menus inside dialogs | ||
// However, if this is a useEffect, it runs twice and dispatches two UPDATE_ACTIVEDESCENDANT and immediately sets | ||
// aria-activeDescendant in useAutocomplete... I've worked around this for now | ||
(0, $i4XHw$react.useEffect)(()=>{ | ||
let isFocused = key === manager.focusedKey; | ||
if (isFocused && manager.isFocused && !shouldUseVirtualFocus) { | ||
if (focus) focus(); | ||
else if (document.activeElement !== ref.current && ref.current) (0, $i4XHw$reactariafocus.focusSafely)(ref.current); | ||
if (isFocused && manager.isFocused) { | ||
if (!shouldUseVirtualFocus) { | ||
if (focus) focus(); | ||
else if (document.activeElement !== ref.current && ref.current) (0, $i4XHw$reactariafocus.focusSafely)(ref.current); | ||
} else { | ||
var _ref_current; | ||
let updateActiveDescendant = new CustomEvent((0, $i4XHw$reactariautils.UPDATE_ACTIVEDESCENDANT), { | ||
cancelable: true, | ||
bubbles: true | ||
}); | ||
(_ref_current = ref.current) === null || _ref_current === void 0 ? void 0 : _ref_current.dispatchEvent(updateActiveDescendant); | ||
} | ||
} | ||
@@ -198,3 +211,4 @@ // eslint-disable-next-line react-hooks/exhaustive-deps | ||
onDragStartCapture: onDragStartCapture, | ||
onClick: onClick | ||
onClick: onClick, | ||
id: id | ||
}), | ||
@@ -201,0 +215,0 @@ isPressed: isPressed, |
@@ -1,4 +0,4 @@ | ||
import {isCtrlKeyPressed as $feb5ffebff200149$export$16792effe837dba3, isNonContiguousSelectionModifier as $feb5ffebff200149$export$d3e3bd3e26688c04} from "./utils.module.js"; | ||
import {isNonContiguousSelectionModifier as $feb5ffebff200149$export$d3e3bd3e26688c04} from "./utils.module.js"; | ||
import {focusSafely as $581M0$focusSafely} from "@react-aria/focus"; | ||
import {useRouter as $581M0$useRouter, openLink as $581M0$openLink, mergeProps as $581M0$mergeProps} from "@react-aria/utils"; | ||
import {useRouter as $581M0$useRouter, useId as $581M0$useId, isCtrlKeyPressed as $581M0$isCtrlKeyPressed, UPDATE_ACTIVEDESCENDANT as $581M0$UPDATE_ACTIVEDESCENDANT, openLink as $581M0$openLink, mergeProps as $581M0$mergeProps} from "@react-aria/utils"; | ||
import {usePress as $581M0$usePress, useLongPress as $581M0$useLongPress} from "@react-aria/interactions"; | ||
@@ -23,4 +23,5 @@ import {useEffect as $581M0$useEffect, useRef as $581M0$useRef} from "react"; | ||
function $880e95eb8b93ba9a$export$ecf600387e221c37(options) { | ||
let { selectionManager: manager, key: key, ref: ref, shouldSelectOnPressUp: shouldSelectOnPressUp, shouldUseVirtualFocus: shouldUseVirtualFocus, focus: focus, isDisabled: isDisabled, onAction: onAction, allowsDifferentPressOrigin: allowsDifferentPressOrigin, linkBehavior: linkBehavior = 'action' } = options; | ||
let { id: id, selectionManager: manager, key: key, ref: ref, shouldSelectOnPressUp: shouldSelectOnPressUp, shouldUseVirtualFocus: shouldUseVirtualFocus, focus: focus, isDisabled: isDisabled, onAction: onAction, allowsDifferentPressOrigin: allowsDifferentPressOrigin, linkBehavior: linkBehavior = 'action' } = options; | ||
let router = (0, $581M0$useRouter)(); | ||
id = (0, $581M0$useId)(id); | ||
let onSelect = (e)=>{ | ||
@@ -43,3 +44,3 @@ if (e.pointerType === 'keyboard' && (0, $feb5ffebff200149$export$d3e3bd3e26688c04)(e)) manager.toggleSelection(key); | ||
} else if (e && e.shiftKey) manager.extendSelection(key); | ||
else if (manager.selectionBehavior === 'toggle' || e && ((0, $feb5ffebff200149$export$16792effe837dba3)(e) || e.pointerType === 'touch' || e.pointerType === 'virtual')) // 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 | ||
else if (manager.selectionBehavior === 'toggle' || e && ((0, $581M0$isCtrlKeyPressed)(e) || e.pointerType === 'touch' || e.pointerType === 'virtual')) // 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 | ||
manager.toggleSelection(key); | ||
@@ -50,7 +51,19 @@ else manager.replaceSelection(key); | ||
// Focus the associated DOM node when this item becomes the focusedKey | ||
// TODO: can't make this useLayoutEffect bacause it breaks menus inside dialogs | ||
// However, if this is a useEffect, it runs twice and dispatches two UPDATE_ACTIVEDESCENDANT and immediately sets | ||
// aria-activeDescendant in useAutocomplete... I've worked around this for now | ||
(0, $581M0$useEffect)(()=>{ | ||
let isFocused = key === manager.focusedKey; | ||
if (isFocused && manager.isFocused && !shouldUseVirtualFocus) { | ||
if (focus) focus(); | ||
else if (document.activeElement !== ref.current && ref.current) (0, $581M0$focusSafely)(ref.current); | ||
if (isFocused && manager.isFocused) { | ||
if (!shouldUseVirtualFocus) { | ||
if (focus) focus(); | ||
else if (document.activeElement !== ref.current && ref.current) (0, $581M0$focusSafely)(ref.current); | ||
} else { | ||
var _ref_current; | ||
let updateActiveDescendant = new CustomEvent((0, $581M0$UPDATE_ACTIVEDESCENDANT), { | ||
cancelable: true, | ||
bubbles: true | ||
}); | ||
(_ref_current = ref.current) === null || _ref_current === void 0 ? void 0 : _ref_current.dispatchEvent(updateActiveDescendant); | ||
} | ||
} | ||
@@ -192,3 +205,4 @@ // eslint-disable-next-line react-hooks/exhaustive-deps | ||
onDragStartCapture: onDragStartCapture, | ||
onClick: onClick | ||
onClick: onClick, | ||
id: id | ||
}), | ||
@@ -195,0 +209,0 @@ isPressed: isPressed, |
@@ -9,3 +9,2 @@ var $gP8Dl$reactariautils = require("@react-aria/utils"); | ||
$parcel$export(module.exports, "isNonContiguousSelectionModifier", () => $ee0bdf4faa47f2a8$export$d3e3bd3e26688c04); | ||
$parcel$export(module.exports, "isCtrlKeyPressed", () => $ee0bdf4faa47f2a8$export$16792effe837dba3); | ||
/* | ||
@@ -27,8 +26,4 @@ * Copyright 2020 Adobe. All rights reserved. | ||
} | ||
function $ee0bdf4faa47f2a8$export$16792effe837dba3(e) { | ||
if ((0, $gP8Dl$reactariautils.isMac)()) return e.metaKey; | ||
return e.ctrlKey; | ||
} | ||
//# sourceMappingURL=utils.main.js.map |
@@ -1,2 +0,2 @@ | ||
import {isAppleDevice as $jUnAJ$isAppleDevice, isMac as $jUnAJ$isMac} from "@react-aria/utils"; | ||
import {isAppleDevice as $jUnAJ$isAppleDevice} from "@react-aria/utils"; | ||
@@ -19,9 +19,5 @@ /* | ||
} | ||
function $feb5ffebff200149$export$16792effe837dba3(e) { | ||
if ((0, $jUnAJ$isMac)()) return e.metaKey; | ||
return e.ctrlKey; | ||
} | ||
export {$feb5ffebff200149$export$d3e3bd3e26688c04 as isNonContiguousSelectionModifier, $feb5ffebff200149$export$16792effe837dba3 as isCtrlKeyPressed}; | ||
export {$feb5ffebff200149$export$d3e3bd3e26688c04 as isNonContiguousSelectionModifier}; | ||
//# sourceMappingURL=utils.module.js.map |
{ | ||
"name": "@react-aria/selection", | ||
"version": "3.0.0-nightly-7eae25e12-241205", | ||
"version": "3.0.0-nightly-801ef48a8-250207", | ||
"description": "Spectrum UI components in React", | ||
@@ -25,8 +25,8 @@ "license": "Apache-2.0", | ||
"dependencies": { | ||
"@react-aria/focus": "^3.0.0-nightly-7eae25e12-241205", | ||
"@react-aria/i18n": "^3.0.0-nightly-7eae25e12-241205", | ||
"@react-aria/interactions": "^3.0.0-nightly-7eae25e12-241205", | ||
"@react-aria/utils": "^3.0.0-nightly-7eae25e12-241205", | ||
"@react-stately/selection": "^3.0.0-nightly-7eae25e12-241205", | ||
"@react-types/shared": "^3.0.0-nightly-7eae25e12-241205", | ||
"@react-aria/focus": "3.0.0-nightly-801ef48a8-250207", | ||
"@react-aria/i18n": "3.0.0-nightly-801ef48a8-250207", | ||
"@react-aria/interactions": "3.0.0-nightly-801ef48a8-250207", | ||
"@react-aria/utils": "3.0.0-nightly-801ef48a8-250207", | ||
"@react-stately/selection": "3.0.0-nightly-801ef48a8-250207", | ||
"@react-types/shared": "3.0.0-nightly-801ef48a8-250207", | ||
"@swc/helpers": "^0.5.0" | ||
@@ -40,4 +40,3 @@ }, | ||
"access": "public" | ||
}, | ||
"stableVersion": "3.21.0" | ||
} | ||
} |
@@ -13,2 +13,3 @@ /* | ||
import {CLEAR_FOCUS_EVENT, FOCUS_EVENT, focusWithoutScrolling, isCtrlKeyPressed, mergeProps, scrollIntoView, scrollIntoViewport, UPDATE_ACTIVEDESCENDANT, useEffectEvent, useEvent, useRouter, useUpdateLayoutEffect} from '@react-aria/utils'; | ||
import {DOMAttributes, FocusableElement, FocusStrategy, Key, KeyboardDelegate, RefObject} from '@react-types/shared'; | ||
@@ -18,5 +19,4 @@ import {flushSync} from 'react-dom'; | ||
import {focusSafely, getFocusableTreeWalker} from '@react-aria/focus'; | ||
import {focusWithoutScrolling, mergeProps, scrollIntoView, scrollIntoViewport, useEvent, useRouter} from '@react-aria/utils'; | ||
import {getInteractionModality} from '@react-aria/interactions'; | ||
import {isCtrlKeyPressed, isNonContiguousSelectionModifier} from './utils'; | ||
import {isNonContiguousSelectionModifier} from './utils'; | ||
import {MultipleSelectionManager} from '@react-stately/selection'; | ||
@@ -347,8 +347,7 @@ import {useLocale} from '@react-aria/i18n'; | ||
manager.setFocused(true); | ||
if (manager.focusedKey == null) { | ||
let navigateToFirstKey = (key: Key | undefined | null) => { | ||
let navigateToKey = (key: Key | undefined | null) => { | ||
if (key != null) { | ||
manager.setFocusedKey(key); | ||
if (selectOnFocus) { | ||
if (selectOnFocus && !manager.isSelected(key)) { | ||
manager.replaceSelection(key); | ||
@@ -363,5 +362,5 @@ } | ||
if (relatedTarget && (e.currentTarget.compareDocumentPosition(relatedTarget) & Node.DOCUMENT_POSITION_FOLLOWING)) { | ||
navigateToFirstKey(manager.lastSelectedKey ?? delegate.getLastKey?.()); | ||
navigateToKey(manager.lastSelectedKey ?? delegate.getLastKey?.()); | ||
} else { | ||
navigateToFirstKey(manager.firstSelectedKey ?? delegate.getFirstKey?.()); | ||
navigateToKey(manager.firstSelectedKey ?? delegate.getFirstKey?.()); | ||
} | ||
@@ -398,2 +397,72 @@ } else if (!isVirtualized && scrollRef.current) { | ||
// Ref to track whether the first item in the collection should be automatically focused. Specifically used for autocomplete when user types | ||
// to focus the first key AFTER the collection updates. | ||
// TODO: potentially expand the usage of this | ||
let shouldVirtualFocusFirst = useRef(false); | ||
// Add event listeners for custom virtual events. These handle updating the focused key in response to various keyboard events | ||
// at the autocomplete level | ||
// TODO: fix type later | ||
useEvent(ref, FOCUS_EVENT, !shouldUseVirtualFocus ? undefined : (e: any) => { | ||
let {detail} = e; | ||
e.stopPropagation(); | ||
manager.setFocused(true); | ||
// If the user is typing forwards, autofocus the first option in the list. | ||
if (detail?.focusStrategy === 'first') { | ||
shouldVirtualFocusFirst.current = true; | ||
} | ||
}); | ||
let updateActiveDescendant = useEffectEvent(() => { | ||
let keyToFocus = delegate.getFirstKey?.() ?? null; | ||
// If no focusable items exist in the list, make sure to clear any activedescendant that may still exist | ||
if (keyToFocus == null) { | ||
ref.current?.dispatchEvent( | ||
new CustomEvent(UPDATE_ACTIVEDESCENDANT, { | ||
cancelable: true, | ||
bubbles: true | ||
}) | ||
); | ||
// 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. | ||
// Reset shouldVirtualFocusFirst so that we don't erronously autofocus an item when the collection is filtered again. | ||
if (manager.collection.size > 0) { | ||
shouldVirtualFocusFirst.current = false; | ||
} | ||
} else { | ||
manager.setFocusedKey(keyToFocus); | ||
// Only set shouldVirtualFocusFirst to false if we've successfully set the first key as the focused key | ||
// 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 | ||
// after the collection updates after load | ||
shouldVirtualFocusFirst.current = false; | ||
} | ||
}); | ||
useUpdateLayoutEffect(() => { | ||
if (shouldVirtualFocusFirst.current) { | ||
updateActiveDescendant(); | ||
} | ||
}, [manager.collection, updateActiveDescendant]); | ||
let resetFocusFirstFlag = useEffectEvent(() => { | ||
// If user causes the focused key to change in any other way, clear shouldVirtualFocusFirst so we don't | ||
// accidentally move focus from under them. Skip this if the collection was empty because we might be in a load | ||
// state and will still want to focus the first item after load | ||
if (manager.collection.size > 0) { | ||
shouldVirtualFocusFirst.current = false; | ||
} | ||
}); | ||
useUpdateLayoutEffect(() => { | ||
resetFocusFirstFlag(); | ||
}, [manager.focusedKey, resetFocusFirstFlag]); | ||
useEvent(ref, CLEAR_FOCUS_EVENT, !shouldUseVirtualFocus ? undefined : (e) => { | ||
e.stopPropagation(); | ||
manager.setFocused(false); | ||
manager.setFocusedKey(null); | ||
}); | ||
const autoFocusRef = useRef(autoFocus); | ||
@@ -494,7 +563,7 @@ useEffect(() => { | ||
// This will be marshalled to either the first or last item depending on where focus came from. | ||
// If using virtual focus, don't set a tabIndex at all so that VoiceOver on iOS 14 doesn't try | ||
// to move real DOM focus to the element anyway. | ||
let tabIndex: number | undefined = undefined; | ||
if (!shouldUseVirtualFocus) { | ||
tabIndex = manager.focusedKey == null ? 0 : -1; | ||
} else { | ||
tabIndex = -1; | ||
} | ||
@@ -501,0 +570,0 @@ |
@@ -13,6 +13,6 @@ /* | ||
import {DOMAttributes, FocusableElement, Key, LongPressEvent, PointerType, PressEvent, RefObject} from '@react-types/shared'; | ||
import {DOMAttributes, DOMProps, FocusableElement, Key, LongPressEvent, PointerType, PressEvent, RefObject} from '@react-types/shared'; | ||
import {focusSafely} from '@react-aria/focus'; | ||
import {isCtrlKeyPressed, isNonContiguousSelectionModifier} from './utils'; | ||
import {mergeProps, openLink, useRouter} from '@react-aria/utils'; | ||
import {isCtrlKeyPressed, mergeProps, openLink, UPDATE_ACTIVEDESCENDANT, useId, useRouter} from '@react-aria/utils'; | ||
import {isNonContiguousSelectionModifier} from './utils'; | ||
import {MultipleSelectionManager} from '@react-stately/selection'; | ||
@@ -22,3 +22,3 @@ import {PressProps, useLongPress, usePress} from '@react-aria/interactions'; | ||
export interface SelectableItemOptions { | ||
export interface SelectableItemOptions extends DOMProps { | ||
/** | ||
@@ -113,2 +113,3 @@ * An interface for reading and updating multiple selection state. | ||
let { | ||
id, | ||
selectionManager: manager, | ||
@@ -126,3 +127,3 @@ key, | ||
let router = useRouter(); | ||
id = useId(id); | ||
let onSelect = (e: PressEvent | LongPressEvent | PointerEvent) => { | ||
@@ -166,9 +167,21 @@ if (e.pointerType === 'keyboard' && isNonContiguousSelectionModifier(e)) { | ||
// Focus the associated DOM node when this item becomes the focusedKey | ||
// TODO: can't make this useLayoutEffect bacause it breaks menus inside dialogs | ||
// However, if this is a useEffect, it runs twice and dispatches two UPDATE_ACTIVEDESCENDANT and immediately sets | ||
// aria-activeDescendant in useAutocomplete... I've worked around this for now | ||
useEffect(() => { | ||
let isFocused = key === manager.focusedKey; | ||
if (isFocused && manager.isFocused && !shouldUseVirtualFocus) { | ||
if (focus) { | ||
focus(); | ||
} else if (document.activeElement !== ref.current && ref.current) { | ||
focusSafely(ref.current); | ||
if (isFocused && manager.isFocused) { | ||
if (!shouldUseVirtualFocus) { | ||
if (focus) { | ||
focus(); | ||
} else if (document.activeElement !== ref.current && ref.current) { | ||
focusSafely(ref.current); | ||
} | ||
} else { | ||
let updateActiveDescendant = new CustomEvent(UPDATE_ACTIVEDESCENDANT, { | ||
cancelable: true, | ||
bubbles: true | ||
}); | ||
ref.current?.dispatchEvent(updateActiveDescendant); | ||
} | ||
@@ -364,3 +377,3 @@ } | ||
longPressEnabled ? longPressProps : {}, | ||
{onDoubleClick, onDragStartCapture, onClick} | ||
{onDoubleClick, onDragStartCapture, onClick, id} | ||
), | ||
@@ -367,0 +380,0 @@ isPressed, |
@@ -13,3 +13,3 @@ /* | ||
import {isAppleDevice, isMac} from '@react-aria/utils'; | ||
import {isAppleDevice} from '@react-aria/utils'; | ||
@@ -27,9 +27,1 @@ interface Event { | ||
} | ||
export function isCtrlKeyPressed(e: Event) { | ||
if (isMac()) { | ||
return e.metaKey; | ||
} | ||
return e.ctrlKey; | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
420074
4681
+ Added@internationalized/date@3.0.0-nightly-801ef48a8-250207(transitive)
+ Added@internationalized/message@3.0.0-nightly-801ef48a8-250207(transitive)
+ Added@internationalized/number@3.0.0-nightly-801ef48a8-250207(transitive)
+ Added@internationalized/string@3.0.0-nightly-801ef48a8-250207(transitive)
+ Added@react-aria/focus@3.0.0-nightly-801ef48a8-250207(transitive)
+ Added@react-aria/i18n@3.0.0-nightly-801ef48a8-250207(transitive)
+ Added@react-aria/interactions@3.0.0-nightly-801ef48a8-250207(transitive)
+ Added@react-aria/ssr@3.0.0-nightly-801ef48a8-250207(transitive)
+ Added@react-aria/utils@3.0.0-nightly-801ef48a8-250207(transitive)
+ Added@react-stately/collections@3.0.0-nightly-801ef48a8-250207(transitive)
+ Added@react-stately/flags@3.0.0-nightly-801ef48a8-250207(transitive)
+ Added@react-stately/selection@3.0.0-nightly-801ef48a8-250207(transitive)
+ Added@react-stately/utils@3.0.0-nightly-801ef48a8-250207(transitive)
+ Added@react-types/shared@3.0.0-nightly-801ef48a8-250207(transitive)
- Removed@internationalized/date@3.7.0(transitive)
- Removed@internationalized/message@3.1.6(transitive)
- Removed@internationalized/number@3.6.0(transitive)
- Removed@internationalized/string@3.2.5(transitive)
- Removed@react-aria/focus@3.19.1(transitive)
- Removed@react-aria/i18n@3.12.5(transitive)
- Removed@react-aria/interactions@3.23.0(transitive)
- Removed@react-aria/ssr@3.9.7(transitive)
- Removed@react-aria/utils@3.27.0(transitive)
- Removed@react-stately/collections@3.12.1(transitive)
- Removed@react-stately/selection@3.19.0(transitive)
- Removed@react-stately/utils@3.10.5(transitive)
- Removed@react-types/shared@3.27.0(transitive)
Updated@react-aria/interactions@3.0.0-nightly-801ef48a8-250207
Updated@react-stately/selection@3.0.0-nightly-801ef48a8-250207