diff --git a/packages/react-aria-components/src/ListBox.tsx b/packages/react-aria-components/src/ListBox.tsx index 721db33ce6f..db19ce65e7a 100644 --- a/packages/react-aria-components/src/ListBox.tsx +++ b/packages/react-aria-components/src/ListBox.tsx @@ -10,7 +10,7 @@ * governing permissions and limitations under the License. */ -import {AriaListBoxOptions, AriaListBoxProps, DraggableItemResult, DragPreviewRenderer, DroppableCollectionResult, DroppableItemResult, FocusScope, ListKeyboardDelegate, mergeProps, useCollator, useFocus, useFocusRing, useHover, useListBox, useListBoxSection, useLocale, useOption} from 'react-aria'; +import {AriaListBoxOptions, AriaListBoxProps, DraggableItemResult, DragPreviewRenderer, DroppableCollectionResult, DroppableItemResult, FocusScope, ListKeyboardDelegate, mergeProps, useCollator, useFocus, useFocusRing, useHover, useKeyboard, useListBox, useListBoxSection, useLocale, useOption} from 'react-aria'; import { ClassNameOrFunction, ContextValue, @@ -30,7 +30,7 @@ import {DragAndDropContext, DropIndicatorContext, DropIndicatorProps, useDndPers import {DragAndDropHooks} from './useDragAndDrop'; import {DraggableCollectionState, DroppableCollectionState, ListState, Node, Orientation, SelectionBehavior, UNSTABLE_useFilteredListState, useListState} from 'react-stately'; import {filterDOMProps, inertValue, LoadMoreSentinelProps, useLoadMoreSentinel, useObjectRef} from '@react-aria/utils'; -import {FocusEvents, forwardRefType, GlobalDOMAttributes, HoverEvents, Key, LinkDOMProps, PressEvents, RefObject} from '@react-types/shared'; +import {FocusEvents, forwardRefType, GlobalDOMAttributes, HoverEvents, Key, KeyboardEvents, LinkDOMProps, PressEvents, RefObject} from '@react-types/shared'; import {HeaderContext} from './Header'; import React, {createContext, ForwardedRef, forwardRef, JSX, ReactNode, useContext, useEffect, useMemo, useRef} from 'react'; import {SelectableCollectionContext, SelectableCollectionContextValue} from './RSPContexts'; @@ -336,7 +336,7 @@ export const ListBoxSection = /*#__PURE__*/ createBranchComponent(SectionNode, L export interface ListBoxItemRenderProps extends ItemRenderProps {} -export interface ListBoxItemProps extends RenderProps, LinkDOMProps, HoverEvents, PressEvents, FocusEvents, Omit, 'onClick'> { +export interface ListBoxItemProps extends RenderProps, LinkDOMProps, HoverEvents, PressEvents, KeyboardEvents, FocusEvents, Omit, 'onClick'> { /** * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. A function may be provided to compute the class based on component state. * @default 'react-aria-ListBoxItem' @@ -379,6 +379,7 @@ export const ListBoxItem = /*#__PURE__*/ createLeafComponent(ItemNode, function onHoverEnd: item.props.onHoverEnd }); + let {keyboardProps} = useKeyboard(props); let {focusProps} = useFocus(props); let draggableItem: DraggableItemResult | null = null; @@ -428,7 +429,7 @@ export const ListBoxItem = /*#__PURE__*/ createLeafComponent(ItemNode, function return ( { act(() => jest.runAllTimers()); expect(onReorder).toHaveBeenCalledTimes(1); - + // Verify we're no longer in drag mode options = getAllByRole('option'); expect(options.filter(opt => opt.classList.contains('react-aria-DropIndicator'))).toHaveLength(0); @@ -1861,4 +1861,26 @@ describe('ListBox', () => { expect(onClick).toHaveBeenCalledTimes(1); }); }); + + describe('onKeyDown', () => { + it('should call key handler when key is pressed on item', async () => { + let onKeyDown = jest.fn((e) => e.continuePropagation()); + let onKeyUp = jest.fn(); + let onSelectionChange = jest.fn(); + renderListbox({selectionMode: 'multiple', onSelectionChange}, {onKeyDown, onKeyUp}); + + await user.tab(); + expect(onKeyUp).toHaveBeenCalledTimes(1); + onKeyUp.mockClear(); + await user.keyboard('{Enter}'); + expect(onKeyDown).toHaveBeenCalledTimes(1); + expect(onKeyUp).toHaveBeenCalledTimes(1); + expect(onSelectionChange).toHaveBeenCalledTimes(1); + + await user.keyboard('{Escape}'); + expect(onKeyDown).toHaveBeenCalledTimes(2); + expect(onKeyUp).toHaveBeenCalledTimes(2); + expect(onSelectionChange).toHaveBeenCalledTimes(2); + }); + }); });