@@ -3,13 +3,13 @@ import * as ReactDOM from '@theia/core/shared/react-dom';
3
3
import { CommandRegistry } from '@theia/core/lib/common/command' ;
4
4
import { DisposableCollection } from '@theia/core/lib/common/disposable' ;
5
5
import { Port } from '../../common/protocol' ;
6
- import { BoardsConfig } from './boards-config' ;
7
6
import { ArduinoCommands } from '../arduino-commands' ;
8
7
import {
9
8
BoardsServiceProvider ,
10
9
AvailableBoard ,
11
10
} from './boards-service-provider' ;
12
11
import { nls } from '@theia/core/lib/common' ;
12
+ import classNames from 'classnames' ;
13
13
14
14
export interface BoardsDropDownListCoords {
15
15
readonly top : number ;
@@ -28,10 +28,12 @@ export namespace BoardsDropDown {
28
28
29
29
export class BoardsDropDown extends React . Component < BoardsDropDown . Props > {
30
30
protected dropdownElement : HTMLElement ;
31
+ private listRef : React . RefObject < HTMLDivElement > ;
31
32
32
33
constructor ( props : BoardsDropDown . Props ) {
33
34
super ( props ) ;
34
35
36
+ this . listRef = React . createRef ( ) ;
35
37
let list = document . getElementById ( 'boards-dropdown-container' ) ;
36
38
if ( ! list ) {
37
39
list = document . createElement ( 'div' ) ;
@@ -41,6 +43,12 @@ export class BoardsDropDown extends React.Component<BoardsDropDown.Props> {
41
43
}
42
44
}
43
45
46
+ override componentDidUpdate ( prevProps : BoardsDropDown . Props ) : void {
47
+ if ( prevProps . coords === 'hidden' && this . listRef . current ) {
48
+ this . listRef . current . focus ( ) ;
49
+ }
50
+ }
51
+
44
52
override render ( ) : React . ReactNode {
45
53
return ReactDOM . createPortal ( this . renderNode ( ) , this . dropdownElement ) ;
46
54
}
@@ -61,21 +69,22 @@ export class BoardsDropDown extends React.Component<BoardsDropDown.Props> {
61
69
position : 'absolute' ,
62
70
...coords ,
63
71
} }
72
+ ref = { this . listRef }
73
+ tabIndex = { 0 }
64
74
>
65
- { items
66
- . map ( ( { name, port, selected, onClick } ) => ( {
67
- label : nls . localize (
68
- 'arduino/board/boardListItem' ,
69
- '{0} at {1}' ,
70
- name ,
71
- Port . toString ( port )
72
- ) ,
73
- selected,
74
- onClick,
75
- } ) )
76
- . map ( this . renderItem ) }
75
+ < div className = "arduino-boards-dropdown-list--items-container" >
76
+ { items
77
+ . map ( ( { name, port, selected, onClick } ) => ( {
78
+ boardLabel : name ,
79
+ port,
80
+ selected,
81
+ onClick,
82
+ } ) )
83
+ . map ( this . renderItem ) }
84
+ </ div >
77
85
< div
78
86
key = { footerLabel }
87
+ tabIndex = { 0 }
79
88
className = "arduino-boards-dropdown-item arduino-board-dropdown-footer"
80
89
onClick = { ( ) => this . props . openBoardsConfig ( ) }
81
90
>
@@ -86,22 +95,49 @@ export class BoardsDropDown extends React.Component<BoardsDropDown.Props> {
86
95
}
87
96
88
97
protected renderItem ( {
89
- label,
98
+ boardLabel,
99
+ port,
90
100
selected,
91
101
onClick,
92
102
} : {
93
- label : string ;
103
+ boardLabel : string ;
104
+ port : Port ;
94
105
selected ?: boolean ;
95
106
onClick : ( ) => void ;
96
107
} ) : React . ReactNode {
108
+ const protocolIcon = iconNameFromProtocol ( port . protocol ) ;
109
+ const onKeyUp = ( e : React . KeyboardEvent ) => {
110
+ if ( e . key === 'Enter' ) {
111
+ onClick ( ) ;
112
+ }
113
+ } ;
114
+
97
115
return (
98
116
< div
99
- key = { label }
100
- className = { `arduino-boards-dropdown-item ${ selected ? 'selected' : '' } ` }
117
+ key = { `board-item--${ boardLabel } -${ port . address } ` }
118
+ className = { classNames ( 'arduino-boards-dropdown-item' , {
119
+ 'arduino-boards-dropdown-item--selected' : selected ,
120
+ } ) }
101
121
onClick = { onClick }
122
+ onKeyUp = { onKeyUp }
123
+ tabIndex = { 0 }
102
124
>
103
- < div > { label } </ div >
104
- { selected ? < span className = "fa fa-check" /> : '' }
125
+ < div
126
+ className = { classNames (
127
+ 'arduino-boards-dropdown-item--protocol' ,
128
+ 'fa' ,
129
+ protocolIcon
130
+ ) }
131
+ />
132
+ < div className = "arduino-boards-dropdown-item--label" >
133
+ < div className = "arduino-boards-dropdown-item--board-label" >
134
+ { boardLabel }
135
+ </ div >
136
+ < div className = "arduino-boards-dropdown-item--port-label" >
137
+ { port . address }
138
+ </ div >
139
+ </ div >
140
+ { selected ? < div className = "fa fa-check" /> : '' }
105
141
</ div >
106
142
) ;
107
143
}
@@ -163,36 +199,43 @@ export class BoardsToolBarItem extends React.Component<
163
199
164
200
override render ( ) : React . ReactNode {
165
201
const { coords, availableBoards } = this . state ;
166
- const boardsConfig = this . props . boardsServiceClient . boardsConfig ;
167
- const title = BoardsConfig . Config . toString ( boardsConfig , {
168
- default : nls . localize (
169
- 'arduino/common/noBoardSelected' ,
170
- 'No board selected'
171
- ) ,
172
- } ) ;
173
- const decorator = ( ( ) => {
174
- const selectedBoard = availableBoards . find ( ( { selected } ) => selected ) ;
175
- if ( ! selectedBoard || ! selectedBoard . port ) {
176
- return 'fa fa-times notAttached' ;
177
- }
178
- if ( selectedBoard . state === AvailableBoard . State . guessed ) {
179
- return 'fa fa-exclamation-triangle guessed' ;
180
- }
181
- return '' ;
182
- } ) ( ) ;
202
+ const selectedBoard = availableBoards . find ( ( { selected } ) => selected ) ;
203
+
204
+ const boardLabel =
205
+ selectedBoard ?. name ||
206
+ nls . localize ( 'arduino/board/selectBoard' , 'Select Board' ) ;
207
+ const selectedPortLabel = portLabel ( selectedBoard ?. port ?. address ) ;
208
+
209
+ const isConnected = Boolean (
210
+ selectedBoard && AvailableBoard . hasPort ( selectedBoard )
211
+ ) ;
212
+ const protocolIcon = isConnected
213
+ ? iconNameFromProtocol ( selectedBoard ?. port ?. protocol || '' )
214
+ : null ;
215
+ const procolIconClassNames = classNames (
216
+ 'arduino-boards-toolbar-item--protocol' ,
217
+ 'fa' ,
218
+ protocolIcon
219
+ ) ;
183
220
184
221
return (
185
222
< React . Fragment >
186
- < div className = "arduino-boards-toolbar-item-container" >
187
- < div className = "arduino-boards-toolbar-item" title = { title } >
188
- < div className = "inner-container" onClick = { this . show } >
189
- < span className = { decorator } />
190
- < div className = "label noWrapInfo" >
191
- < div className = "noWrapInfo noselect" > { title } </ div >
192
- </ div >
193
- < span className = "fa fa-caret-down caret" />
194
- </ div >
223
+ < div
224
+ className = "arduino-boards-toolbar-item-container"
225
+ title = { selectedPortLabel }
226
+ onClick = { this . show }
227
+ >
228
+ { protocolIcon && < div className = { procolIconClassNames } /> }
229
+ < div
230
+ className = { classNames (
231
+ 'arduino-boards-toolbar-item--label' ,
232
+ 'noWrapInfo noselect' ,
233
+ { 'arduino-boards-toolbar-item--label-connected' : isConnected }
234
+ ) }
235
+ >
236
+ { boardLabel }
195
237
</ div >
238
+ < div className = "fa fa-caret-down caret" />
196
239
</ div >
197
240
< BoardsDropDown
198
241
coords = { coords }
@@ -212,6 +255,7 @@ export class BoardsToolBarItem extends React.Component<
212
255
selectedPort : board . port ,
213
256
} ;
214
257
}
258
+ this . setState ( { coords : 'hidden' } ) ;
215
259
} ,
216
260
} ) ) }
217
261
openBoardsConfig = { this . openDialog }
@@ -222,7 +266,6 @@ export class BoardsToolBarItem extends React.Component<
222
266
223
267
protected openDialog = ( ) => {
224
268
this . props . commands . executeCommand ( ArduinoCommands . OPEN_BOARDS_DIALOG . id ) ;
225
- this . setState ( { coords : 'hidden' } ) ;
226
269
} ;
227
270
}
228
271
export namespace BoardsToolBarItem {
@@ -236,3 +279,26 @@ export namespace BoardsToolBarItem {
236
279
coords : BoardsDropDownListCoords | 'hidden' ;
237
280
}
238
281
}
282
+
283
+ function iconNameFromProtocol ( protocol : string ) : string {
284
+ switch ( protocol ) {
285
+ case 'serial' :
286
+ return 'fa-arduino-technology-usb' ;
287
+ case 'network' :
288
+ return 'fa-arduino-technology-connection' ;
289
+ /*
290
+ Bluetooth ports are not listed yet from the CLI;
291
+ Not sure about the naming ('bluetooth'); make sure it's correct before uncommenting the following lines
292
+ */
293
+ // case 'bluetooth':
294
+ // return 'fa-arduino-technology-bluetooth';
295
+ default :
296
+ return 'fa-arduino-technology-3dimensionscube' ;
297
+ }
298
+ }
299
+
300
+ function portLabel ( portName ?: string ) : string {
301
+ return portName
302
+ ? nls . localize ( 'arduino/board/portLabel' , 'Port: {0}' , portName )
303
+ : nls . localize ( 'arduino/board/disconnected' , 'Disconnected' ) ;
304
+ }
0 commit comments