@@ -5,6 +5,7 @@ import Flex from "@/components/templates/flex"
55import Search from "@/components/search"
66import Box from "@/components/templates/box"
77import { mergeRefs } from "@/utils"
8+ import { useCallback } from "react"
89
910const Container = styled ( Flex ) `
1011 ${ ( { hideShadow } ) =>
@@ -15,6 +16,19 @@ const Container = styled(Flex)`
1516
1617const defaultEstimateSize = ( ) => 28
1718
19+ const indexCalculatorByKey = {
20+ ArrowDown : ( index , length ) => Math . min ( index + 1 , length - 1 ) ,
21+ ArrowUp : index => Math . max ( index - 1 , 0 ) ,
22+ Home : ( ) => 0 ,
23+ End : ( _ , length ) => length - 1 ,
24+ default : index => index ,
25+ }
26+
27+ const getNextIndex = ( currentIndex , key , itemsLength ) => {
28+ const calculator = indexCalculatorByKey [ key ] || indexCalculatorByKey . default
29+ return calculator ( currentIndex , itemsLength )
30+ }
31+
1832const Dropdown = forwardRef (
1933 (
2034 {
@@ -32,6 +46,9 @@ const Dropdown = forwardRef(
3246 gap = 0 ,
3347 estimateSize = defaultEstimateSize ,
3448 close,
49+ enableKeyNavigation,
50+ activeIndex,
51+ setActiveIndex,
3552 ...rest
3653 } ,
3754 forwardedRef
@@ -61,6 +78,31 @@ const Dropdown = forwardRef(
6178 estimateSize,
6279 } )
6380
81+ const handleKeyDown = useCallback (
82+ event => {
83+ if ( [ "ArrowDown" , "ArrowUp" , "Home" , "End" ] . includes ( event . code ) ) {
84+ setActiveIndex ( prevIndex => {
85+ const nextIndex = getNextIndex ( prevIndex , event . code , items . length )
86+ rowVirtualizer . scrollToIndex ( nextIndex )
87+ return nextIndex
88+ } )
89+ }
90+ } ,
91+ [ rowVirtualizer , items , setActiveIndex ]
92+ )
93+
94+ const virtualContainerProps = useMemo ( ( ) => {
95+ if ( enableKeyNavigation )
96+ return {
97+ tabIndex : 0 ,
98+ role : "listbox" ,
99+ "aria-activedescendant" : `item-${ activeIndex } ` ,
100+ onKeyDown : handleKeyDown ,
101+ }
102+
103+ return { }
104+ } , [ enableKeyNavigation , activeIndex , handleKeyDown ] )
105+
64106 return (
65107 < Container
66108 as = "ul"
@@ -86,6 +128,7 @@ const Dropdown = forwardRef(
86128 height : "100%" ,
87129 overflow : "auto" ,
88130 } }
131+ { ...virtualContainerProps }
89132 >
90133 < div
91134 style = { {
@@ -116,6 +159,7 @@ const Dropdown = forwardRef(
116159 value = { value }
117160 onItemClick = { onItemClick }
118161 close = { close }
162+ { ...( enableKeyNavigation ? { enableKeyNavigation : true , activeIndex } : { } ) }
119163 />
120164 </ div >
121165 ) ) }
0 commit comments