@@ -66,6 +66,7 @@ function GeneratorTitle({ title, gen }: GeneratorTitleProps) {
6666 const [ active , setActive ] = useFocus ( )
6767 const [ search , setSearch ] = useState ( '' )
6868 const inputRef = useRef < HTMLInputElement > ( null )
69+ const resultsRef = useRef < HTMLDivElement > ( null )
6970
7071 const icon = Object . keys ( Icons ) . includes ( gen . id ) ? gen . id as keyof typeof Icons : undefined
7172
@@ -92,14 +93,41 @@ function GeneratorTitle({ title, gen }: GeneratorTitleProps) {
9293 } )
9394 } , [ setActive , inputRef ] )
9495
96+ const handleKeyDown = useCallback ( ( e : KeyboardEvent ) => {
97+ if ( e . key == 'Enter' ) {
98+ if ( document . activeElement == inputRef . current ) {
99+ const firstResult = resultsRef . current ?. firstElementChild
100+ if ( firstResult instanceof HTMLElement ) {
101+ firstResult . click ( )
102+ }
103+ }
104+ } else if ( e . key == 'ArrowDown' ) {
105+ const nextElement = document . activeElement == inputRef . current
106+ ? resultsRef . current ?. firstElementChild
107+ : document . activeElement ?. nextElementSibling
108+ if ( nextElement instanceof HTMLElement ) {
109+ nextElement . focus ( )
110+ }
111+ e . preventDefault ( )
112+ } else if ( e . key == 'ArrowUp' ) {
113+ const prevElement = document . activeElement ?. previousElementSibling
114+ if ( prevElement instanceof HTMLElement ) {
115+ prevElement . focus ( )
116+ }
117+ e . preventDefault ( )
118+ } else if ( e . key == 'Escape' ) {
119+ setActive ( false )
120+ }
121+ } , [ setActive , inputRef ] )
122+
95123 return < div class = "px-1 relative" >
96124 < h1 class = "font-bold flex items-center cursor-pointer text-lg sm:text-2xl" onClick = { open } >
97125 { title }
98126 { icon && Icons [ icon ] }
99127 </ h1 >
100- < div class = { `gen-menu absolute flex flex-col gap-2 p-2 rounded-lg drop-shadow-xl ${ active ? '' : 'hidden' } ` } >
101- < input ref = { inputRef } type = "text" class = "py-1 px-2 w-full rounded" value = { search } placeholder = { locale ( 'generators.search' ) } onInput = { ( e ) => setSearch ( ( e . target as HTMLInputElement ) . value ) } onClick = { e => e . stopPropagation ( ) } />
102- { active && < div class = "gen-results overflow-y-auto overscroll-none flex flex-col pr-2 h-96 max-h-max min-w-max" >
128+ < div class = { `gen-menu absolute flex flex-col gap-2 p-2 rounded-lg drop-shadow-xl ${ active ? '' : 'hidden' } ` } onKeyDown = { handleKeyDown } >
129+ < input ref = { inputRef } type = "text" class = "py-1 px-2 w-full rounded" value = { search } placeholder = { locale ( 'generators.search' ) } onInput = { ( e ) => setSearch ( ( e . target as HTMLInputElement ) . value ) } onClick = { ( e ) => e . stopPropagation ( ) } />
130+ { active && < div ref = { resultsRef } class = "gen-results overflow-y-auto overscroll-none flex flex-col pr-2 h-96 max-h-max min-w-max" >
103131 { generators . length === 0 && < span class = "note" > { locale ( 'generators.no_results' ) } </ span > }
104132 { generators . map ( g =>
105133 < Link class = "flex items-center cursor-pointer no-underline rounded p-1" href = { cleanUrl ( g . url ) } onClick = { ( ) => setActive ( false ) } >
0 commit comments