1
+ // src/features/docs/doc-tree/hooks/useDropdownKeyboardNav.ts
1
2
import { RefObject , useEffect } from 'react' ;
2
3
3
- import { DropdownMenuOption } from '../DropdownMenu' ;
4
+ import { DropdownMenuOption } from '@/components/DropdownMenu' ;
5
+
6
+ import { useKeyboardActivation } from './useKeyboardActivation' ;
4
7
5
8
type UseDropdownKeyboardNavProps = {
6
9
isOpen : boolean ;
@@ -19,64 +22,65 @@ export const useDropdownKeyboardNav = ({
19
22
setFocusedIndex,
20
23
onOpenChange,
21
24
} : UseDropdownKeyboardNavProps ) => {
25
+ useKeyboardActivation ( [ 'Enter' , ' ' ] , isOpen , ( ) => {
26
+ if ( focusedIndex === - 1 ) {
27
+ return ;
28
+ }
29
+
30
+ const enabledIndices = options
31
+ . map ( ( opt , i ) => ( opt . show !== false && ! opt . disabled ? i : - 1 ) )
32
+ . filter ( ( i ) => i !== - 1 ) ;
33
+
34
+ const selectedOpt = options [ enabledIndices [ focusedIndex ] ] ;
35
+ if ( selectedOpt ?. callback ) {
36
+ onOpenChange ( false ) ;
37
+ void selectedOpt . callback ( ) ;
38
+ }
39
+ } ) ;
40
+
22
41
useEffect ( ( ) => {
23
42
const handleKeyDown = ( event : KeyboardEvent ) => {
24
43
if ( ! isOpen ) {
25
44
return ;
26
45
}
27
46
28
47
const enabledIndices = options
29
- . map ( ( option , index ) =>
30
- option . show !== false && ! option . disabled ? index : - 1 ,
31
- )
32
- . filter ( ( index ) => index !== - 1 ) ;
48
+ . map ( ( opt , i ) => ( opt . show !== false && ! opt . disabled ? i : - 1 ) )
49
+ . filter ( ( i ) => i !== - 1 ) ;
33
50
34
51
switch ( event . key ) {
35
- case 'ArrowDown' :
52
+ case 'ArrowDown' : {
36
53
event . preventDefault ( ) ;
37
54
const nextIndex =
38
55
focusedIndex < enabledIndices . length - 1 ? focusedIndex + 1 : 0 ;
39
- const nextEnabledIndex = enabledIndices [ nextIndex ] ;
56
+ const nextEnabled = enabledIndices [ nextIndex ] ;
40
57
setFocusedIndex ( nextIndex ) ;
41
- menuItemRefs . current [ nextEnabledIndex ] ?. focus ( ) ;
58
+ menuItemRefs . current [ nextEnabled ] ?. focus ( ) ;
42
59
break ;
60
+ }
43
61
44
- case 'ArrowUp' :
62
+ case 'ArrowUp' : {
45
63
event . preventDefault ( ) ;
46
64
const prevIndex =
47
65
focusedIndex > 0 ? focusedIndex - 1 : enabledIndices . length - 1 ;
48
- const prevEnabledIndex = enabledIndices [ prevIndex ] ;
66
+ const prevEnabled = enabledIndices [ prevIndex ] ;
49
67
setFocusedIndex ( prevIndex ) ;
50
- menuItemRefs . current [ prevEnabledIndex ] ?. focus ( ) ;
68
+ menuItemRefs . current [ prevEnabled ] ?. focus ( ) ;
51
69
break ;
70
+ }
52
71
53
- case 'Enter' :
54
- case ' ' :
55
- event . preventDefault ( ) ;
56
- if ( focusedIndex >= 0 && focusedIndex < enabledIndices . length ) {
57
- const selectedOptionIndex = enabledIndices [ focusedIndex ] ;
58
- const selectedOption = options [ selectedOptionIndex ] ;
59
- if ( selectedOption && selectedOption . callback ) {
60
- onOpenChange ( false ) ;
61
- void selectedOption . callback ( ) ;
62
- }
63
- }
64
- break ;
65
-
66
- case 'Escape' :
72
+ case 'Escape' : {
67
73
event . preventDefault ( ) ;
68
74
onOpenChange ( false ) ;
69
75
break ;
76
+ }
70
77
}
71
78
} ;
72
79
73
80
if ( isOpen ) {
74
81
document . addEventListener ( 'keydown' , handleKeyDown ) ;
75
82
}
76
-
77
- return ( ) => {
78
- document . removeEventListener ( 'keydown' , handleKeyDown ) ;
79
- } ;
83
+ return ( ) => document . removeEventListener ( 'keydown' , handleKeyDown ) ;
80
84
} , [
81
85
isOpen ,
82
86
focusedIndex ,
0 commit comments