-
Notifications
You must be signed in to change notification settings - Fork 377
feat(Select/Dropdown/MenuContainer): arrow key handling to focus items #11132
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
0fe487a
039e095
fd712a7
fdbc8b3
513c6f5
cdd6f0f
de44721
901e606
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -62,6 +62,10 @@ export interface SelectProps extends MenuProps, OUIAProps { | |
| onOpenChange?: (isOpen: boolean) => void; | ||
| /** Keys that trigger onOpenChange, defaults to tab and escape. It is highly recommended to include Escape in the array, while Tab may be omitted if the menu contains non-menu items that are focusable. */ | ||
| onOpenChangeKeys?: string[]; | ||
| /** Custom callback to override the default behaviour when pressing up/down arrows. Default is focusing the menu items (first item on arrow down, last item on arrow up). */ | ||
| onArrowUpDownKeyDown?: (event: KeyboardEvent) => void; | ||
| /** Indicates that the Select is used as a typeahead (combobox). Focus won't shift to menu items when pressing up/down arrows. */ | ||
| isTypeahead?: boolean; | ||
|
||
| /** Indicates if the select should be without the outer box-shadow */ | ||
| isPlain?: boolean; | ||
| /** @hide Forwarded ref */ | ||
|
|
@@ -95,6 +99,8 @@ const SelectBase: React.FunctionComponent<SelectProps & OUIAProps> = ({ | |
| shouldFocusFirstItemOnOpen = false, | ||
| onOpenChange, | ||
| onOpenChangeKeys = ['Escape', 'Tab'], | ||
| onArrowUpDownKeyDown, | ||
| isTypeahead, | ||
| isPlain, | ||
| innerRef, | ||
| zIndex = 9999, | ||
|
|
@@ -131,6 +137,21 @@ const SelectBase: React.FunctionComponent<SelectProps & OUIAProps> = ({ | |
| }, [isOpen]); | ||
|
|
||
| React.useEffect(() => { | ||
| const onArrowUpDownKeyDownDefault = (event: KeyboardEvent) => { | ||
| event.preventDefault(); | ||
|
|
||
| let listItem: HTMLLIElement; | ||
| if (event.key === 'ArrowDown') { | ||
| listItem = menuRef.current?.querySelector('li'); | ||
| } else { | ||
| const allItems = menuRef.current?.querySelectorAll('li'); | ||
| listItem = allItems ? allItems[allItems.length - 1] : null; | ||
| } | ||
|
|
||
| const focusableElement = listItem?.querySelector('button:not(:disabled),input:not(:disabled)'); | ||
kmcfaul marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| focusableElement && (focusableElement as HTMLElement).focus(); | ||
| }; | ||
|
|
||
| const handleMenuKeys = (event: KeyboardEvent) => { | ||
| // Close the menu on tab or escape if onOpenChange is provided | ||
| if ( | ||
|
|
@@ -144,6 +165,14 @@ const SelectBase: React.FunctionComponent<SelectProps & OUIAProps> = ({ | |
| toggleRef.current?.focus(); | ||
| } | ||
| } | ||
|
|
||
| if (event.key === 'ArrowDown' || event.key === 'ArrowUp') { | ||
| if (onArrowUpDownKeyDown) { | ||
| onArrowUpDownKeyDown(event); | ||
| } else if (!isTypeahead) { | ||
| onArrowUpDownKeyDownDefault(event); | ||
| } | ||
| } | ||
| }; | ||
|
|
||
| const handleClick = (event: MouseEvent) => { | ||
|
|
@@ -168,6 +197,7 @@ const SelectBase: React.FunctionComponent<SelectProps & OUIAProps> = ({ | |
| toggleRef, | ||
| onOpenChange, | ||
| onOpenChangeKeys, | ||
| onArrowUpDownKeyDown, | ||
| shouldPreventScrollOnItemFocus, | ||
| shouldFocusFirstItemOnOpen, | ||
| focusTimeoutDelay | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.