1
- import { useEffect , useState } from 'react'
1
+ import { useEffect , useRef , useState } from 'react'
2
2
3
3
import {
4
4
API_STATUS_CODES ,
@@ -7,8 +7,10 @@ import {
7
7
KeyboardShortcut ,
8
8
ResponseType ,
9
9
SearchBar ,
10
+ stopPropagation ,
10
11
useQuery ,
11
12
useRegisterShortcut ,
13
+ UseRegisterShortcutProvider ,
12
14
} from '@devtron-labs/devtron-fe-common-lib'
13
15
14
16
import CommandGroup from './CommandGroup'
@@ -19,6 +21,7 @@ import './CommandBar.scss'
19
21
20
22
const CommandBar = ( ) => {
21
23
const [ showCommandBar , setShowCommandBar ] = useState ( false )
24
+ const [ searchText , setSearchText ] = useState ( '' )
22
25
23
26
const { data : recentActionsGroup , isLoading } = useQuery ( {
24
27
queryFn : ( { signal } ) =>
@@ -48,25 +51,54 @@ const CommandBar = () => {
48
51
} , structuredClone ( RECENT_ACTIONS_GROUP ) ) ,
49
52
} )
50
53
54
+ const searchBarRef = useRef < HTMLInputElement > ( null )
55
+
51
56
const { registerShortcut, unregisterShortcut } = useRegisterShortcut ( )
52
57
58
+ const handleSearchChange = ( value : string ) => {
59
+ setSearchText ( value )
60
+ }
61
+
53
62
const handleClose = ( ) => {
63
+ setSearchText ( '' )
54
64
setShowCommandBar ( false )
55
65
}
56
66
67
+ const handleEscape = ( ) => {
68
+ if ( searchText ) {
69
+ handleSearchChange ( '' )
70
+ return
71
+ }
72
+
73
+ handleClose ( )
74
+ }
75
+
57
76
const handleOpen = ( ) => {
58
77
setShowCommandBar ( true )
59
78
}
60
79
80
+ const focusSearchBar = ( ) => {
81
+ if ( searchBarRef . current ) {
82
+ searchBarRef . current . focus ( )
83
+ }
84
+ }
85
+
61
86
useEffect ( ( ) => {
62
87
registerShortcut ( {
63
88
keys : SHORT_CUTS . OPEN_COMMAND_BAR . keys ,
64
- description : 'Open Command Bar' ,
89
+ description : SHORT_CUTS . OPEN_COMMAND_BAR . description ,
65
90
callback : handleOpen ,
66
91
} )
67
92
93
+ registerShortcut ( {
94
+ keys : SHORT_CUTS . FOCUS_SEARCH_BAR . keys ,
95
+ description : SHORT_CUTS . FOCUS_SEARCH_BAR . description ,
96
+ callback : focusSearchBar ,
97
+ } )
98
+
68
99
return ( ) => {
69
100
unregisterShortcut ( SHORT_CUTS . OPEN_COMMAND_BAR . keys )
101
+ unregisterShortcut ( SHORT_CUTS . FOCUS_SEARCH_BAR . keys )
70
102
}
71
103
} , [ ] )
72
104
@@ -75,59 +107,67 @@ const CommandBar = () => {
75
107
}
76
108
77
109
return (
78
- < Backdrop onEscape = { handleClose } >
79
- < div className = "dc__mxw-800 mxh-450 flexbox-col dc__overflow-auto dc__content-space br-12 bg__modal--primary command-bar__container w-100 h-100" >
80
- < div className = "flexbox-col dc__overflow-auto" >
81
- < div className = "px-20 py-8" >
82
- < SearchBar
83
- inputProps = { {
84
- autoFocus : true ,
85
- placeholder : 'Search or jump to…' ,
86
- } }
87
- noBackgroundAndBorder
88
- />
89
- </ div >
90
-
91
- < div
92
- className = "flexbox-col dc__overflow-auto border__primary--top pt-8"
93
- role = "listbox"
94
- aria-label = "Command Menu"
95
- // TODO: aria-activedescendant for the currently focused item
96
- >
97
- < CommandGroup isLoading = { isLoading } { ...( recentActionsGroup || RECENT_ACTIONS_GROUP ) } />
98
-
99
- { NAVIGATION_GROUPS . map ( ( group ) => (
100
- < CommandGroup key = { group . id } { ...group } />
101
- ) ) }
102
- </ div >
103
- </ div >
110
+ < UseRegisterShortcutProvider ignoreTags = { [ ] } >
111
+ < Backdrop onEscape = { handleEscape } onClick = { handleClose } deactivateFocusOnEscape = { ! ! searchText } >
112
+ < div
113
+ onClick = { stopPropagation }
114
+ className = "dc__mxw-800 mxh-450 flexbox-col dc__overflow-auto dc__content-space br-12 bg__modal--primary command-bar__container w-100 h-100"
115
+ >
116
+ < div className = "flexbox-col dc__overflow-auto" >
117
+ < div className = "px-20 py-8" >
118
+ < SearchBar
119
+ inputProps = { {
120
+ autoFocus : true ,
121
+ placeholder : 'Search or jump to…' ,
122
+ ref : searchBarRef ,
123
+ } }
124
+ initialSearchText = { searchText }
125
+ handleSearchChange = { handleSearchChange }
126
+ noBackgroundAndBorder
127
+ />
128
+ </ div >
104
129
105
- < div className = "flexbox dc__content-space dc__align-items-center px-20 py-12 border__primary--top bg__secondary" >
106
- < div className = "flexbox dc__gap-20 dc__align-items-center" >
107
- < div className = "flexbox dc__gap-8 dc__align-items-center" >
108
- < KeyboardShortcut keyboardKey = "ArrowUp" />
109
- < KeyboardShortcut keyboardKey = "ArrowDown" />
110
- < span className = "cn-9 fs-12 fw-4 lh-20" > to navigate</ span >
130
+ < div
131
+ className = "flexbox-col dc__overflow-auto border__primary--top pt-8"
132
+ role = "listbox"
133
+ aria-label = "Command Menu"
134
+ // TODO: aria-activedescendant for the currently focused item
135
+ >
136
+ < CommandGroup isLoading = { isLoading } { ...( recentActionsGroup || RECENT_ACTIONS_GROUP ) } />
137
+
138
+ { NAVIGATION_GROUPS . map ( ( group ) => (
139
+ < CommandGroup key = { group . id } { ...group } />
140
+ ) ) }
111
141
</ div >
142
+ </ div >
112
143
113
- < div className = "flexbox dc__gap-8 dc__align-items-center" >
114
- < KeyboardShortcut keyboardKey = "Enter" />
115
- < span className = "cn-9 fs-12 fw-4 lh-20" > to select</ span >
144
+ < div className = "flexbox dc__content-space dc__align-items-center px-20 py-12 border__primary--top bg__secondary" >
145
+ < div className = "flexbox dc__gap-20 dc__align-items-center" >
146
+ < div className = "flexbox dc__gap-8 dc__align-items-center" >
147
+ < KeyboardShortcut keyboardKey = "ArrowUp" />
148
+ < KeyboardShortcut keyboardKey = "ArrowDown" />
149
+ < span className = "cn-9 fs-12 fw-4 lh-20" > to navigate</ span >
150
+ </ div >
151
+
152
+ < div className = "flexbox dc__gap-8 dc__align-items-center" >
153
+ < KeyboardShortcut keyboardKey = "Enter" />
154
+ < span className = "cn-9 fs-12 fw-4 lh-20" > to select</ span >
155
+ </ div >
156
+
157
+ < div className = "flexbox dc__gap-8 dc__align-items-center" >
158
+ < KeyboardShortcut keyboardKey = "Escape" />
159
+ < span className = "cn-9 fs-12 fw-4 lh-20" > to close</ span >
160
+ </ div >
116
161
</ div >
117
162
118
163
< div className = "flexbox dc__gap-8 dc__align-items-center" >
119
- < KeyboardShortcut keyboardKey = "Escape " />
120
- < span className = "cn-9 fs-12 fw-4 lh-20" > to close </ span >
164
+ < KeyboardShortcut keyboardKey = "> " />
165
+ < span className = "cn-9 fs-12 fw-4 lh-20" > to search actions </ span >
121
166
</ div >
122
167
</ div >
123
-
124
- < div className = "flexbox dc__gap-8 dc__align-items-center" >
125
- < KeyboardShortcut keyboardKey = ">" />
126
- < span className = "cn-9 fs-12 fw-4 lh-20" > to search actions</ span >
127
- </ div >
128
168
</ div >
129
- </ div >
130
- </ Backdrop >
169
+ </ Backdrop >
170
+ </ UseRegisterShortcutProvider >
131
171
)
132
172
}
133
173
0 commit comments