@react-aria/selection
Advanced tools
Comparing version 3.1.0 to 3.2.0
131
dist/main.js
@@ -6,2 +6,7 @@ var { | ||
var { | ||
mergeProps | ||
} = require("@react-aria/utils"); | ||
var { | ||
focusSafely, | ||
getFocusableTreeWalker | ||
@@ -11,7 +16,2 @@ } = require("@react-aria/focus"); | ||
var { | ||
focusWithoutScrolling, | ||
mergeProps | ||
} = require("@react-aria/utils"); | ||
var { | ||
useEffect, | ||
@@ -22,2 +22,8 @@ useRef, | ||
var _babelRuntimeHelpersExtends = $parcel$interopDefault(require("@babel/runtime/helpers/extends")); | ||
function $parcel$interopDefault(a) { | ||
return a && a.__esModule ? a.default : a; | ||
} | ||
/** | ||
@@ -42,2 +48,11 @@ * Handles typeahead interactions with collections. | ||
return; | ||
} // Do not propagate the Spacebar event if it's meant to be part of the search. | ||
// When we time out, the search term becomes empty, hence the check on length. | ||
// Trimming is to account for the case of pressing the Spacebar more than once, | ||
// which should cycle through the selection/deselection of the focused item. | ||
if (character === ' ' && state.search.trim().length > 0) { | ||
e.preventDefault(); | ||
e.stopPropagation(); | ||
} | ||
@@ -68,3 +83,5 @@ | ||
typeSelectProps: { | ||
onKeyDown: keyboardDelegate.getKeyForSearch ? onKeyDown : null | ||
// Using a capturing listener to catch the keydown event before | ||
// other hooks in order to handle the Spacebar event. | ||
onKeyDownCapture: keyboardDelegate.getKeyForSearch ? onKeyDown : null | ||
} | ||
@@ -109,3 +126,5 @@ }; | ||
disallowEmptySelection = false, | ||
disallowSelectAll = false | ||
disallowSelectAll = false, | ||
selectOnFocus = false, | ||
disallowTypeAhead = false | ||
} = options; | ||
@@ -130,4 +149,13 @@ | ||
manager.setFocusedKey(nextKey); | ||
if (manager.selectionMode === 'single' && selectOnFocus) { | ||
manager.replaceSelection(nextKey); | ||
} | ||
} else if (shouldFocusWrap) { | ||
manager.setFocusedKey(delegate.getFirstKey(manager.focusedKey)); | ||
let wrapKey = delegate.getFirstKey(manager.focusedKey); | ||
manager.setFocusedKey(wrapKey); | ||
if (manager.selectionMode === 'single' && selectOnFocus) { | ||
manager.replaceSelection(wrapKey); | ||
} | ||
} | ||
@@ -151,4 +179,13 @@ | ||
manager.setFocusedKey(nextKey); | ||
if (manager.selectionMode === 'single' && selectOnFocus) { | ||
manager.replaceSelection(nextKey); | ||
} | ||
} else if (shouldFocusWrap) { | ||
manager.setFocusedKey(delegate.getLastKey(manager.focusedKey)); | ||
let wrapKey = delegate.getLastKey(manager.focusedKey); | ||
manager.setFocusedKey(wrapKey); | ||
if (manager.selectionMode === 'single' && selectOnFocus) { | ||
manager.replaceSelection(wrapKey); | ||
} | ||
} | ||
@@ -172,2 +209,6 @@ | ||
manager.setFocusedKey(nextKey); | ||
if (manager.selectionMode === 'single' && selectOnFocus) { | ||
manager.replaceSelection(nextKey); | ||
} | ||
} | ||
@@ -191,2 +232,6 @@ | ||
manager.setFocusedKey(nextKey); | ||
if (manager.selectionMode === 'single' && selectOnFocus) { | ||
manager.replaceSelection(nextKey); | ||
} | ||
} | ||
@@ -208,2 +253,6 @@ | ||
if (manager.selectionMode === 'single' && selectOnFocus) { | ||
manager.replaceSelection(firstKey); | ||
} | ||
if ($f791fefd7189e0e4d903034fb2925$var$isCtrlKeyPressed(e) && e.shiftKey && manager.selectionMode === 'multiple') { | ||
@@ -222,2 +271,6 @@ manager.extendSelection(firstKey); | ||
if (manager.selectionMode === 'single' && selectOnFocus) { | ||
manager.replaceSelection(lastKey); | ||
} | ||
if ($f791fefd7189e0e4d903034fb2925$var$isCtrlKeyPressed(e) && e.shiftKey && manager.selectionMode === 'multiple') { | ||
@@ -338,5 +391,9 @@ manager.extendSelection(lastKey); | ||
if (relatedTarget && e.currentTarget.compareDocumentPosition(relatedTarget) & Node.DOCUMENT_POSITION_FOLLOWING) { | ||
manager.setFocusedKey(delegate.getLastKey()); | ||
var _manager$lastSelected; | ||
manager.setFocusedKey((_manager$lastSelected = manager.lastSelectedKey) != null ? _manager$lastSelected : delegate.getLastKey()); | ||
} else { | ||
manager.setFocusedKey(delegate.getFirstKey()); | ||
var _manager$firstSelecte; | ||
manager.setFocusedKey((_manager$firstSelecte = manager.firstSelectedKey) != null ? _manager$firstSelecte : delegate.getFirstKey()); | ||
} | ||
@@ -376,3 +433,3 @@ } | ||
if (focusedKey == null) { | ||
focusWithoutScrolling(ref.current); | ||
focusSafely(ref.current); | ||
} | ||
@@ -382,2 +439,16 @@ } // eslint-disable-next-line react-hooks/exhaustive-deps | ||
}, []); | ||
let handlers = { | ||
// We use a capturing listener to ensure that the keyboard events for the collection | ||
// override those of the children. For example, ArrowDown in a table should always go | ||
// to the cell below, and not open a menu. | ||
onKeyDownCapture: onKeyDown, | ||
onFocus, | ||
onBlur, | ||
onMouseDown(e) { | ||
// Prevent focus going to the collection when clicking on the scrollbar. | ||
e.preventDefault(); | ||
} | ||
}; | ||
let { | ||
@@ -389,17 +460,12 @@ typeSelectProps | ||
}); | ||
return { | ||
collectionProps: mergeProps(typeSelectProps, { | ||
tabIndex: -1, | ||
// We use a capturing listener to ensure that the keyboard events for the collection | ||
// override those of the children. For example, ArrowDown in a table should always go | ||
// to the cell below, and not open a menu. | ||
onKeyDownCapture: onKeyDown, | ||
onFocus, | ||
onBlur, | ||
onMouseDown(e) { | ||
// Prevent focus going to the collection when clicking on the scrollbar. | ||
e.preventDefault(); | ||
} | ||
if (!disallowTypeAhead) { | ||
handlers = mergeProps(typeSelectProps, handlers); | ||
} | ||
return { | ||
collectionProps: _babelRuntimeHelpersExtends({}, handlers, { | ||
// If nothing is focused within the collection, make the collection itself tabbable. | ||
// This will be marshalled to either the first or last item depending on where focus came from. | ||
tabIndex: manager.focusedKey == null ? 0 : -1 | ||
}) | ||
@@ -421,2 +487,3 @@ }; | ||
isVirtualized, | ||
shouldUseVirtualFocus, | ||
focus | ||
@@ -446,10 +513,10 @@ } = options; | ||
useEffect(() => { | ||
if (isFocused && manager.isFocused && document.activeElement !== ref.current) { | ||
if (isFocused && manager.isFocused && !shouldUseVirtualFocus && document.activeElement !== ref.current) { | ||
if (focus) { | ||
focus(); | ||
} else { | ||
focusWithoutScrolling(ref.current); | ||
focusSafely(ref.current); | ||
} | ||
} | ||
}, [ref, isFocused, manager.focusedKey, manager.isFocused]); | ||
}, [ref, isFocused, manager.focusedKey, manager.isFocused, shouldUseVirtualFocus]); | ||
let itemProps = { | ||
@@ -668,3 +735,5 @@ tabIndex: isFocused ? 0 : -1, | ||
isVirtualized, | ||
disallowEmptySelection | ||
disallowEmptySelection, | ||
selectOnFocus = false, | ||
disallowTypeAhead | ||
} = props; // By default, a KeyboardDelegate is provided which uses the DOM to query layout information (e.g. for page up/page down). | ||
@@ -697,3 +766,5 @@ // When virtualized, the layout object will be passed in as a prop and override this. | ||
shouldFocusWrap, | ||
disallowEmptySelection | ||
disallowEmptySelection, | ||
selectOnFocus, | ||
disallowTypeAhead | ||
}); | ||
@@ -700,0 +771,0 @@ return { |
import { useCollator } from "@react-aria/i18n"; | ||
import { getFocusableTreeWalker } from "@react-aria/focus"; | ||
import { focusWithoutScrolling, mergeProps } from "@react-aria/utils"; | ||
import { mergeProps } from "@react-aria/utils"; | ||
import { focusSafely, getFocusableTreeWalker } from "@react-aria/focus"; | ||
import { useEffect, useRef, useMemo } from "react"; | ||
import _babelRuntimeHelpersEsmExtends from "@babel/runtime/helpers/esm/extends"; | ||
@@ -25,2 +26,11 @@ /** | ||
return; | ||
} // Do not propagate the Spacebar event if it's meant to be part of the search. | ||
// When we time out, the search term becomes empty, hence the check on length. | ||
// Trimming is to account for the case of pressing the Spacebar more than once, | ||
// which should cycle through the selection/deselection of the focused item. | ||
if (character === ' ' && state.search.trim().length > 0) { | ||
e.preventDefault(); | ||
e.stopPropagation(); | ||
} | ||
@@ -51,3 +61,5 @@ | ||
typeSelectProps: { | ||
onKeyDown: keyboardDelegate.getKeyForSearch ? onKeyDown : null | ||
// Using a capturing listener to catch the keydown event before | ||
// other hooks in order to handle the Spacebar event. | ||
onKeyDownCapture: keyboardDelegate.getKeyForSearch ? onKeyDown : null | ||
} | ||
@@ -90,3 +102,5 @@ }; | ||
disallowEmptySelection = false, | ||
disallowSelectAll = false | ||
disallowSelectAll = false, | ||
selectOnFocus = false, | ||
disallowTypeAhead = false | ||
} = options; | ||
@@ -111,4 +125,13 @@ | ||
manager.setFocusedKey(nextKey); | ||
if (manager.selectionMode === 'single' && selectOnFocus) { | ||
manager.replaceSelection(nextKey); | ||
} | ||
} else if (shouldFocusWrap) { | ||
manager.setFocusedKey(delegate.getFirstKey(manager.focusedKey)); | ||
let wrapKey = delegate.getFirstKey(manager.focusedKey); | ||
manager.setFocusedKey(wrapKey); | ||
if (manager.selectionMode === 'single' && selectOnFocus) { | ||
manager.replaceSelection(wrapKey); | ||
} | ||
} | ||
@@ -132,4 +155,13 @@ | ||
manager.setFocusedKey(nextKey); | ||
if (manager.selectionMode === 'single' && selectOnFocus) { | ||
manager.replaceSelection(nextKey); | ||
} | ||
} else if (shouldFocusWrap) { | ||
manager.setFocusedKey(delegate.getLastKey(manager.focusedKey)); | ||
let wrapKey = delegate.getLastKey(manager.focusedKey); | ||
manager.setFocusedKey(wrapKey); | ||
if (manager.selectionMode === 'single' && selectOnFocus) { | ||
manager.replaceSelection(wrapKey); | ||
} | ||
} | ||
@@ -153,2 +185,6 @@ | ||
manager.setFocusedKey(nextKey); | ||
if (manager.selectionMode === 'single' && selectOnFocus) { | ||
manager.replaceSelection(nextKey); | ||
} | ||
} | ||
@@ -172,2 +208,6 @@ | ||
manager.setFocusedKey(nextKey); | ||
if (manager.selectionMode === 'single' && selectOnFocus) { | ||
manager.replaceSelection(nextKey); | ||
} | ||
} | ||
@@ -189,2 +229,6 @@ | ||
if (manager.selectionMode === 'single' && selectOnFocus) { | ||
manager.replaceSelection(firstKey); | ||
} | ||
if ($a9b9aa71af07c56ab1d89ca45381f4b$var$isCtrlKeyPressed(e) && e.shiftKey && manager.selectionMode === 'multiple') { | ||
@@ -203,2 +247,6 @@ manager.extendSelection(firstKey); | ||
if (manager.selectionMode === 'single' && selectOnFocus) { | ||
manager.replaceSelection(lastKey); | ||
} | ||
if ($a9b9aa71af07c56ab1d89ca45381f4b$var$isCtrlKeyPressed(e) && e.shiftKey && manager.selectionMode === 'multiple') { | ||
@@ -319,5 +367,9 @@ manager.extendSelection(lastKey); | ||
if (relatedTarget && e.currentTarget.compareDocumentPosition(relatedTarget) & Node.DOCUMENT_POSITION_FOLLOWING) { | ||
manager.setFocusedKey(delegate.getLastKey()); | ||
var _manager$lastSelected; | ||
manager.setFocusedKey((_manager$lastSelected = manager.lastSelectedKey) != null ? _manager$lastSelected : delegate.getLastKey()); | ||
} else { | ||
manager.setFocusedKey(delegate.getFirstKey()); | ||
var _manager$firstSelecte; | ||
manager.setFocusedKey((_manager$firstSelecte = manager.firstSelectedKey) != null ? _manager$firstSelecte : delegate.getFirstKey()); | ||
} | ||
@@ -357,3 +409,3 @@ } | ||
if (focusedKey == null) { | ||
focusWithoutScrolling(ref.current); | ||
focusSafely(ref.current); | ||
} | ||
@@ -363,2 +415,16 @@ } // eslint-disable-next-line react-hooks/exhaustive-deps | ||
}, []); | ||
let handlers = { | ||
// We use a capturing listener to ensure that the keyboard events for the collection | ||
// override those of the children. For example, ArrowDown in a table should always go | ||
// to the cell below, and not open a menu. | ||
onKeyDownCapture: onKeyDown, | ||
onFocus, | ||
onBlur, | ||
onMouseDown(e) { | ||
// Prevent focus going to the collection when clicking on the scrollbar. | ||
e.preventDefault(); | ||
} | ||
}; | ||
let { | ||
@@ -370,17 +436,12 @@ typeSelectProps | ||
}); | ||
return { | ||
collectionProps: mergeProps(typeSelectProps, { | ||
tabIndex: -1, | ||
// We use a capturing listener to ensure that the keyboard events for the collection | ||
// override those of the children. For example, ArrowDown in a table should always go | ||
// to the cell below, and not open a menu. | ||
onKeyDownCapture: onKeyDown, | ||
onFocus, | ||
onBlur, | ||
onMouseDown(e) { | ||
// Prevent focus going to the collection when clicking on the scrollbar. | ||
e.preventDefault(); | ||
} | ||
if (!disallowTypeAhead) { | ||
handlers = mergeProps(typeSelectProps, handlers); | ||
} | ||
return { | ||
collectionProps: _babelRuntimeHelpersEsmExtends({}, handlers, { | ||
// If nothing is focused within the collection, make the collection itself tabbable. | ||
// This will be marshalled to either the first or last item depending on where focus came from. | ||
tabIndex: manager.focusedKey == null ? 0 : -1 | ||
}) | ||
@@ -400,2 +461,3 @@ }; | ||
isVirtualized, | ||
shouldUseVirtualFocus, | ||
focus | ||
@@ -425,10 +487,10 @@ } = options; | ||
useEffect(() => { | ||
if (isFocused && manager.isFocused && document.activeElement !== ref.current) { | ||
if (isFocused && manager.isFocused && !shouldUseVirtualFocus && document.activeElement !== ref.current) { | ||
if (focus) { | ||
focus(); | ||
} else { | ||
focusWithoutScrolling(ref.current); | ||
focusSafely(ref.current); | ||
} | ||
} | ||
}, [ref, isFocused, manager.focusedKey, manager.isFocused]); | ||
}, [ref, isFocused, manager.focusedKey, manager.isFocused, shouldUseVirtualFocus]); | ||
let itemProps = { | ||
@@ -643,3 +705,5 @@ tabIndex: isFocused ? 0 : -1, | ||
isVirtualized, | ||
disallowEmptySelection | ||
disallowEmptySelection, | ||
selectOnFocus = false, | ||
disallowTypeAhead | ||
} = props; // By default, a KeyboardDelegate is provided which uses the DOM to query layout information (e.g. for page up/page down). | ||
@@ -672,3 +736,5 @@ // When virtualized, the layout object will be passed in as a prop and override this. | ||
shouldFocusWrap, | ||
disallowEmptySelection | ||
disallowEmptySelection, | ||
selectOnFocus, | ||
disallowTypeAhead | ||
}); | ||
@@ -675,0 +741,0 @@ return { |
@@ -62,2 +62,12 @@ import { HTMLAttributes, Key, RefObject } from "react"; | ||
disallowSelectAll?: boolean; | ||
/** | ||
* Whether selection should occur automatically on focus. | ||
* @default false | ||
*/ | ||
selectOnFocus?: boolean; | ||
/** | ||
* Whether typeahead is disabled. | ||
* @default false | ||
*/ | ||
disallowTypeAhead?: boolean; | ||
} | ||
@@ -98,2 +108,6 @@ interface SelectableCollectionAria { | ||
focus?: () => void; | ||
/** | ||
* Whether the option should use virtual focus instead of being focused directly. | ||
*/ | ||
shouldUseVirtualFocus?: boolean; | ||
} | ||
@@ -160,2 +174,12 @@ interface SelectableItemAria { | ||
disallowEmptySelection?: boolean; | ||
/** | ||
* Whether selection should occur automatically on focus. | ||
* @default false | ||
*/ | ||
selectOnFocus?: boolean; | ||
/** | ||
* Whether typeahead is disabled. | ||
* @default false | ||
*/ | ||
disallowTypeAhead?: boolean; | ||
} | ||
@@ -162,0 +186,0 @@ interface SelectableListAria { |
{ | ||
"name": "@react-aria/selection", | ||
"version": "3.1.0", | ||
"version": "3.2.0", | ||
"description": "Spectrum UI components in React", | ||
@@ -21,9 +21,9 @@ "license": "Apache-2.0", | ||
"@babel/runtime": "^7.6.2", | ||
"@react-aria/focus": "^3.1.0", | ||
"@react-aria/focus": "^3.2.0", | ||
"@react-aria/i18n": "^3.1.0", | ||
"@react-aria/interactions": "^3.1.0", | ||
"@react-aria/utils": "^3.1.0", | ||
"@react-stately/collections": "^3.1.0", | ||
"@react-stately/selection": "^3.1.0", | ||
"@react-types/shared": "^3.1.0" | ||
"@react-aria/interactions": "^3.2.0", | ||
"@react-aria/utils": "^3.2.0", | ||
"@react-stately/collections": "^3.2.0", | ||
"@react-stately/selection": "^3.2.0", | ||
"@react-types/shared": "^3.2.0" | ||
}, | ||
@@ -36,3 +36,3 @@ "peerDependencies": { | ||
}, | ||
"gitHead": "211099972fe75ee581892efd01a7f89dfb9cdf69" | ||
"gitHead": "661f0f2e3b8648a75aae83043267954700059fe0" | ||
} |
@@ -14,5 +14,4 @@ /* | ||
import {FocusEvent, HTMLAttributes, KeyboardEvent, RefObject, useEffect} from 'react'; | ||
import {focusSafely, getFocusableTreeWalker} from '@react-aria/focus'; | ||
import {FocusStrategy, KeyboardDelegate} from '@react-types/shared'; | ||
import {focusWithoutScrolling} from '@react-aria/utils'; | ||
import {getFocusableTreeWalker} from '@react-aria/focus'; | ||
import {mergeProps} from '@react-aria/utils'; | ||
@@ -67,3 +66,13 @@ import {MultipleSelectionManager} from '@react-stately/selection'; | ||
*/ | ||
disallowSelectAll?: boolean | ||
disallowSelectAll?: boolean, | ||
/** | ||
* Whether selection should occur automatically on focus. | ||
* @default false | ||
*/ | ||
selectOnFocus?: boolean, | ||
/** | ||
* Whether typeahead is disabled. | ||
* @default false | ||
*/ | ||
disallowTypeAhead?: boolean | ||
} | ||
@@ -87,3 +96,5 @@ | ||
disallowEmptySelection = false, | ||
disallowSelectAll = false | ||
disallowSelectAll = false, | ||
selectOnFocus = false, | ||
disallowTypeAhead = false | ||
} = options; | ||
@@ -109,4 +120,11 @@ | ||
manager.setFocusedKey(nextKey); | ||
if (manager.selectionMode === 'single' && selectOnFocus) { | ||
manager.replaceSelection(nextKey); | ||
} | ||
} else if (shouldFocusWrap) { | ||
manager.setFocusedKey(delegate.getFirstKey(manager.focusedKey)); | ||
let wrapKey = delegate.getFirstKey(manager.focusedKey); | ||
manager.setFocusedKey(wrapKey); | ||
if (manager.selectionMode === 'single' && selectOnFocus) { | ||
manager.replaceSelection(wrapKey); | ||
} | ||
} | ||
@@ -129,4 +147,11 @@ | ||
manager.setFocusedKey(nextKey); | ||
if (manager.selectionMode === 'single' && selectOnFocus) { | ||
manager.replaceSelection(nextKey); | ||
} | ||
} else if (shouldFocusWrap) { | ||
manager.setFocusedKey(delegate.getLastKey(manager.focusedKey)); | ||
let wrapKey = delegate.getLastKey(manager.focusedKey); | ||
manager.setFocusedKey(wrapKey); | ||
if (manager.selectionMode === 'single' && selectOnFocus) { | ||
manager.replaceSelection(wrapKey); | ||
} | ||
} | ||
@@ -146,2 +171,5 @@ | ||
manager.setFocusedKey(nextKey); | ||
if (manager.selectionMode === 'single' && selectOnFocus) { | ||
manager.replaceSelection(nextKey); | ||
} | ||
} | ||
@@ -160,2 +188,5 @@ if (e.shiftKey && manager.selectionMode === 'multiple') { | ||
manager.setFocusedKey(nextKey); | ||
if (manager.selectionMode === 'single' && selectOnFocus) { | ||
manager.replaceSelection(nextKey); | ||
} | ||
} | ||
@@ -173,2 +204,5 @@ if (e.shiftKey && manager.selectionMode === 'multiple') { | ||
manager.setFocusedKey(firstKey); | ||
if (manager.selectionMode === 'single' && selectOnFocus) { | ||
manager.replaceSelection(firstKey); | ||
} | ||
if (isCtrlKeyPressed(e) && e.shiftKey && manager.selectionMode === 'multiple') { | ||
@@ -184,2 +218,5 @@ manager.extendSelection(firstKey); | ||
manager.setFocusedKey(lastKey); | ||
if (manager.selectionMode === 'single' && selectOnFocus) { | ||
manager.replaceSelection(lastKey); | ||
} | ||
if (isCtrlKeyPressed(e) && e.shiftKey && manager.selectionMode === 'multiple') { | ||
@@ -278,5 +315,5 @@ manager.extendSelection(lastKey); | ||
if (relatedTarget && (e.currentTarget.compareDocumentPosition(relatedTarget) & Node.DOCUMENT_POSITION_FOLLOWING)) { | ||
manager.setFocusedKey(delegate.getLastKey()); | ||
manager.setFocusedKey(manager.lastSelectedKey ?? delegate.getLastKey()); | ||
} else { | ||
manager.setFocusedKey(delegate.getFirstKey()); | ||
manager.setFocusedKey(manager.firstSelectedKey ?? delegate.getFirstKey()); | ||
} | ||
@@ -315,3 +352,3 @@ } | ||
if (focusedKey == null) { | ||
focusWithoutScrolling(ref.current); | ||
focusSafely(ref.current); | ||
} | ||
@@ -322,2 +359,15 @@ } | ||
let handlers = { | ||
// We use a capturing listener to ensure that the keyboard events for the collection | ||
// override those of the children. For example, ArrowDown in a table should always go | ||
// to the cell below, and not open a menu. | ||
onKeyDownCapture: onKeyDown, | ||
onFocus, | ||
onBlur, | ||
onMouseDown(e) { | ||
// Prevent focus going to the collection when clicking on the scrollbar. | ||
e.preventDefault(); | ||
} | ||
}; | ||
let {typeSelectProps} = useTypeSelect({ | ||
@@ -328,17 +378,14 @@ keyboardDelegate: delegate, | ||
if (!disallowTypeAhead) { | ||
handlers = mergeProps(typeSelectProps, handlers); | ||
} | ||
return { | ||
collectionProps: mergeProps(typeSelectProps, { | ||
tabIndex: -1, | ||
// We use a capturing listener to ensure that the keyboard events for the collection | ||
// override those of the children. For example, ArrowDown in a table should always go | ||
// to the cell below, and not open a menu. | ||
onKeyDownCapture: onKeyDown, | ||
onFocus, | ||
onBlur, | ||
onMouseDown(e) { | ||
// Prevent focus going to the collection when clicking on the scrollbar. | ||
e.preventDefault(); | ||
} | ||
}) | ||
collectionProps: { | ||
...handlers, | ||
// If nothing is focused within the collection, make the collection itself tabbable. | ||
// This will be marshalled to either the first or last item depending on where focus came from. | ||
tabIndex: manager.focusedKey == null ? 0 : -1 | ||
} | ||
}; | ||
} |
@@ -13,3 +13,3 @@ /* | ||
import {focusWithoutScrolling} from '@react-aria/utils'; | ||
import {focusSafely} from '@react-aria/focus'; | ||
import {HTMLAttributes, Key, RefObject, useEffect} from 'react'; | ||
@@ -45,3 +45,7 @@ import {MultipleSelectionManager} from '@react-stately/selection'; | ||
*/ | ||
focus?: () => void | ||
focus?: () => void, | ||
/** | ||
* Whether the option should use virtual focus instead of being focused directly. | ||
*/ | ||
shouldUseVirtualFocus?: boolean | ||
} | ||
@@ -66,2 +70,3 @@ | ||
isVirtualized, | ||
shouldUseVirtualFocus, | ||
focus | ||
@@ -91,10 +96,10 @@ } = options; | ||
useEffect(() => { | ||
if (isFocused && manager.isFocused && document.activeElement !== ref.current) { | ||
if (isFocused && manager.isFocused && !shouldUseVirtualFocus && document.activeElement !== ref.current) { | ||
if (focus) { | ||
focus(); | ||
} else { | ||
focusWithoutScrolling(ref.current); | ||
focusSafely(ref.current); | ||
} | ||
} | ||
}, [ref, isFocused, manager.focusedKey, manager.isFocused]); | ||
}, [ref, isFocused, manager.focusedKey, manager.isFocused, shouldUseVirtualFocus]); | ||
@@ -101,0 +106,0 @@ let itemProps: SelectableItemAria['itemProps'] = { |
@@ -59,3 +59,13 @@ /* | ||
*/ | ||
disallowEmptySelection?: boolean | ||
disallowEmptySelection?: boolean, | ||
/** | ||
* Whether selection should occur automatically on focus. | ||
* @default false | ||
*/ | ||
selectOnFocus?: boolean, | ||
/** | ||
* Whether typeahead is disabled. | ||
* @default false | ||
*/ | ||
disallowTypeAhead?: boolean | ||
} | ||
@@ -83,3 +93,5 @@ | ||
isVirtualized, | ||
disallowEmptySelection | ||
disallowEmptySelection, | ||
selectOnFocus = false, | ||
disallowTypeAhead | ||
} = props; | ||
@@ -109,3 +121,5 @@ | ||
shouldFocusWrap, | ||
disallowEmptySelection | ||
disallowEmptySelection, | ||
selectOnFocus, | ||
disallowTypeAhead | ||
}); | ||
@@ -112,0 +126,0 @@ |
@@ -55,2 +55,11 @@ /* | ||
// Do not propagate the Spacebar event if it's meant to be part of the search. | ||
// When we time out, the search term becomes empty, hence the check on length. | ||
// Trimming is to account for the case of pressing the Spacebar more than once, | ||
// which should cycle through the selection/deselection of the focused item. | ||
if (character === ' ' && state.search.trim().length > 0) { | ||
e.preventDefault(); | ||
e.stopPropagation(); | ||
} | ||
state.search += character; | ||
@@ -80,3 +89,5 @@ | ||
typeSelectProps: { | ||
onKeyDown: keyboardDelegate.getKeyForSearch ? onKeyDown : null | ||
// Using a capturing listener to catch the keydown event before | ||
// other hooks in order to handle the Spacebar event. | ||
onKeyDownCapture: keyboardDelegate.getKeyForSearch ? onKeyDown : null | ||
} | ||
@@ -83,0 +94,0 @@ }; |
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
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
196199
2291