1
1
2
2
import React , { Component , PureComponent } from 'react' ;
3
3
import { connect } from 'react-redux'
4
- import { bindActionCreators } from 'redux'
4
+ import { Dispatch , bindActionCreators } from 'redux'
5
5
import { SortableContainer , SortableElement , arrayMove } from '../external/react-sortable-hoc'
6
6
7
7
import classnames from 'classnames'
8
8
9
9
import ContextMenuArea from './ContextMenuArea'
10
10
11
11
import CharGrid from '../components/CharGrid'
12
- import { Framebuffer } from '../redux/editor'
13
- import { Toolbar } from '../redux/toolbar'
14
- import * as Screens from '../redux/screens'
12
+ import * as framebuf from '../redux/editor'
13
+ import * as toolbar from '../redux/toolbar'
14
+ import * as screens from '../redux/screens'
15
15
import * as selectors from '../redux/selectors'
16
16
import * as screensSelectors from '../redux/screensSelectors'
17
17
import { getSettingsCurrentColorPalette } from '../redux/settingsSelectors'
@@ -23,11 +23,28 @@ import { faPlus } from '@fortawesome/free-solid-svg-icons'
23
23
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
24
24
25
25
import styles from './FramebufferTabs.module.css'
26
+ import { Framebuf , Rgb , Font , RootState } from '../redux/types' ;
27
+
28
+ interface NameInputDispatchProps {
29
+ Toolbar : toolbar . PropsFromDispatch ;
30
+ }
31
+
32
+ interface NameInputProps {
33
+ name : string ;
34
+
35
+ onSubmit : ( name : string ) => void ;
36
+ onCancel : ( ) => void ;
37
+ onBlur : ( ) => void ;
38
+ }
39
+
40
+ interface NameInputState {
41
+ name : string ;
42
+ }
26
43
27
44
// This class is a bit funky with how it disables/enables keyboard shortcuts
28
45
// globally for the app while the input element has focus. Maybe there'd be a
29
46
// better way to do this, but this seems to work.
30
- class NameInput_ extends Component {
47
+ class NameInput_ extends Component < NameInputProps & NameInputDispatchProps , NameInputState > {
31
48
state = {
32
49
name : this . props . name
33
50
}
@@ -36,32 +53,34 @@ class NameInput_ extends Component {
36
53
this . props . Toolbar . setShortcutsActive ( true )
37
54
}
38
55
39
- handleSubmit = ( e ) => {
56
+ handleSubmit = ( e : React . FormEvent < HTMLFormElement > ) => {
40
57
e . preventDefault ( )
41
58
this . props . onSubmit ( this . state . name )
42
59
this . props . Toolbar . setShortcutsActive ( true )
43
60
}
44
61
45
- handleChange = ( e ) => {
46
- this . setState ( { name : e . target . value } )
62
+ handleChange = ( e : React . FormEvent < EventTarget > ) => {
63
+ let target = e . target as HTMLInputElement ;
64
+ this . setState ( { name : target . value } )
47
65
}
48
66
49
- handleKeyDown = ( e ) => {
67
+ handleKeyDown = ( e : React . KeyboardEvent ) => {
50
68
if ( e . key === 'Escape' ) {
51
69
e . preventDefault ( )
52
70
this . props . onCancel ( )
53
71
this . props . Toolbar . setShortcutsActive ( true )
54
72
}
55
73
}
56
74
57
- handleBlur = ( e ) => {
75
+ handleBlur = ( _e : React . FormEvent < HTMLInputElement > ) => {
58
76
this . props . onBlur ( )
59
77
this . props . Toolbar . setShortcutsActive ( true )
60
78
}
61
79
62
- handleFocus = ( e ) => {
80
+ handleFocus = ( e : React . FormEvent < HTMLInputElement > ) => {
81
+ let target = e . target as HTMLInputElement ;
63
82
this . props . Toolbar . setShortcutsActive ( false )
64
- e . target . select ( )
83
+ target . select ( )
65
84
}
66
85
67
86
render ( ) {
@@ -90,17 +109,27 @@ class NameInput_ extends Component {
90
109
91
110
const NameInput = connect (
92
111
null ,
93
- ( dispatch , ownProps ) => {
112
+ ( dispatch ) => {
94
113
return {
95
- Toolbar : Toolbar . bindDispatch ( dispatch )
114
+ Toolbar : bindActionCreators ( toolbar . Toolbar . actions , dispatch )
96
115
}
97
116
}
98
117
) ( NameInput_ )
99
118
100
119
101
- class NameEditor extends Component {
120
+ interface NameEditorProps {
121
+ name : string ;
122
+
123
+ onNameSave : ( name : string ) => void ;
124
+ }
125
+
126
+ interface NameEditorState {
127
+ editing : boolean ;
128
+ }
129
+
130
+ class NameEditor extends Component < NameEditorProps , NameEditorState > {
102
131
state = {
103
- editing : false ,
132
+ editing : false
104
133
}
105
134
106
135
handleEditingClick = ( ) => {
@@ -111,7 +140,7 @@ class NameEditor extends Component {
111
140
this . setState ( { editing : false } )
112
141
}
113
142
114
- handleSubmit = ( name ) => {
143
+ handleSubmit = ( name : string ) => {
115
144
this . setState ( { editing : false } )
116
145
this . props . onNameSave ( name )
117
146
}
@@ -139,7 +168,21 @@ class NameEditor extends Component {
139
168
}
140
169
}
141
170
142
- class FramebufTab extends PureComponent {
171
+ interface FramebufTabProps {
172
+ id : number ;
173
+ active : boolean ;
174
+ framebufId : number ;
175
+ framebuf : Framebuf ;
176
+ colorPalette : Rgb [ ] ;
177
+ font : Font ;
178
+
179
+ setName : ( name : string , framebufId : number ) => void ;
180
+ onSetActiveTab : ( id : number ) => void ;
181
+ onDuplicateTab : ( id : number ) => void ;
182
+ onRemoveTab : ( id : number ) => void ;
183
+ } ;
184
+
185
+ class FramebufTab extends PureComponent < FramebufTabProps > {
143
186
handleSelect = ( ) => {
144
187
this . props . onSetActiveTab ( this . props . id )
145
188
}
@@ -152,7 +195,7 @@ class FramebufTab extends PureComponent {
152
195
this . props . onRemoveTab ( this . props . id )
153
196
}
154
197
155
- handleNameSave = ( name ) => {
198
+ handleNameSave = ( name : string ) => {
156
199
if ( name !== '' ) {
157
200
this . props . setName ( name , this . props . framebufId )
158
201
}
@@ -223,28 +266,43 @@ class FramebufTab extends PureComponent {
223
266
</ div >
224
267
</ ContextMenuArea >
225
268
< NameEditor
226
- name = { fp . maybeDefault ( this . props . framebuf . name , 'Untitled' ) }
269
+ name = { fp . maybeDefault ( this . props . framebuf . name , 'Untitled' as string ) }
227
270
onNameSave = { this . handleNameSave }
228
271
/>
229
272
</ div >
230
273
)
231
274
}
232
275
}
233
276
234
- const SortableFramebufTab = SortableElement ( ( props ) =>
277
+ const SortableFramebufTab = SortableElement ( ( props : FramebufTabProps ) =>
235
278
< FramebufTab { ...props } />
236
279
)
237
280
238
- const SortableTabList = SortableContainer ( ( { children} ) => {
281
+ const SortableTabList = SortableContainer ( ( props : { children : any } ) => {
239
282
return (
240
283
< div className = { styles . tabs } >
241
- { children }
284
+ { props . children }
242
285
</ div >
243
286
)
244
287
} )
245
288
246
- class FramebufferTabs_ extends Component {
247
- handleActiveClick = ( idx ) => {
289
+ interface FramebufferTabsDispatch {
290
+ Screens : screens . PropsFromDispatch ;
291
+ Toolbar : toolbar . PropsFromDispatch ;
292
+ }
293
+
294
+ interface FramebufferTabsProps {
295
+ screens : number [ ] ;
296
+ activeScreen : number ;
297
+ colorPalette : Rgb [ ] ;
298
+
299
+ getFramebufByIndex : ( framebufId : number ) => Framebuf | null ;
300
+ getFont : ( framebuf : Framebuf ) => Font ;
301
+ setFramebufName : ( name : string ) => void ;
302
+ }
303
+
304
+ class FramebufferTabs_ extends Component < FramebufferTabsProps & FramebufferTabsDispatch > {
305
+ handleActiveClick = ( idx : number ) => {
248
306
this . props . Screens . setCurrentScreenIndex ( idx )
249
307
}
250
308
@@ -254,25 +312,25 @@ class FramebufferTabs_ extends Component {
254
312
this . props . Toolbar . setCtrlKey ( false )
255
313
}
256
314
257
- handleRemoveTab = ( idx ) => {
315
+ handleRemoveTab = ( idx : number ) => {
258
316
this . props . Screens . removeScreen ( idx )
259
317
// Context menu eats the ctrl key up event, so force it to false
260
318
this . props . Toolbar . setCtrlKey ( false )
261
319
}
262
320
263
- handleDuplicateTab = ( idx ) => {
321
+ handleDuplicateTab = ( idx : number ) => {
264
322
this . props . Screens . cloneScreen ( idx )
265
323
// Context menu eats the ctrl key up event, so force it to false
266
324
this . props . Toolbar . setCtrlKey ( false )
267
325
}
268
326
269
- onSortEnd = ( { oldIndex, newIndex} ) => {
270
- this . props . Screens . setScreenOrder ( arrayMove ( this . props . screens , oldIndex , newIndex ) )
327
+ onSortEnd = ( args : { oldIndex : number , newIndex : number } ) => {
328
+ this . props . Screens . setScreenOrder ( arrayMove ( this . props . screens , args . oldIndex , args . newIndex ) )
271
329
}
272
330
273
331
render ( ) {
274
332
const lis = this . props . screens . map ( ( framebufId , i ) => {
275
- const framebuf = this . props . getFramebufByIndex ( framebufId )
333
+ const framebuf = this . props . getFramebufByIndex ( framebufId ) !
276
334
return (
277
335
< SortableFramebufTab
278
336
key = { framebufId }
@@ -286,10 +344,13 @@ class FramebufferTabs_ extends Component {
286
344
active = { i === this . props . activeScreen }
287
345
font = { this . props . getFont ( framebuf ) }
288
346
colorPalette = { this . props . colorPalette }
289
- setName = { this . props . Framebuffer . setName }
347
+ setName = { this . props . setFramebufName }
290
348
/>
291
349
)
292
350
} )
351
+ // onClick is not in FontAwesomeIcon props and don't know how to pass
352
+ // it otherwise.
353
+ const typingWorkaround = { onClick : this . handleNewTab } ;
293
354
return (
294
355
< div className = { styles . tabHeadings } >
295
356
< SortableTabList
@@ -300,32 +361,36 @@ class FramebufferTabs_ extends Component {
300
361
>
301
362
{ lis }
302
363
< div className = { classnames ( styles . tab , styles . newScreen ) } >
303
- < FontAwesomeIcon onClick = { this . handleNewTab } icon = { faPlus } />
364
+ < FontAwesomeIcon { ... typingWorkaround } icon = { faPlus } />
304
365
</ div >
305
366
</ SortableTabList >
306
367
</ div >
307
368
)
308
369
}
309
370
}
310
371
311
- const mapDispatchToProps = ( dispatch , ownProps ) => {
312
- return {
313
- Toolbar : Toolbar . bindDispatch ( dispatch ) ,
314
- Framebuffer : Framebuffer . bindDispatch ( dispatch ) ,
315
- Screens : bindActionCreators ( Screens . actions , dispatch )
316
- }
317
- }
318
-
319
- const mapStateToProps = state => {
320
- return {
321
- activeScreen : screensSelectors . getCurrentScreenIndex ( state ) ,
322
- screens : screensSelectors . getScreens ( state ) ,
323
- getFramebufByIndex : ( idx ) => selectors . getFramebufByIndex ( state , idx ) ,
324
- getFont : ( fb ) => selectors . getFramebufFont ( state , fb ) ,
325
- colorPalette : getSettingsCurrentColorPalette ( state )
326
- }
327
- }
328
372
export default connect (
329
- mapStateToProps ,
330
- mapDispatchToProps ,
373
+ ( state : RootState ) => {
374
+ return {
375
+ activeScreen : screensSelectors . getCurrentScreenIndex ( state ) ,
376
+ screens : screensSelectors . getScreens ( state ) ,
377
+ getFramebufByIndex : ( idx : number ) => selectors . getFramebufByIndex ( state , idx ) ,
378
+ getFont : ( fb : Framebuf ) => selectors . getFramebufFont ( state , fb ) ,
379
+ colorPalette : getSettingsCurrentColorPalette ( state )
380
+ }
381
+ } ,
382
+ ( dispatch ) => {
383
+ return {
384
+ Toolbar : toolbar . Toolbar . bindDispatch ( dispatch ) ,
385
+ Screens : bindActionCreators ( screens . actions , dispatch ) ,
386
+ setFramebufName : ( name : string ) => {
387
+ return ( dispatch : Dispatch , getState : ( ) => RootState ) => {
388
+ const framebufIndex = screensSelectors . getCurrentScreenFramebufIndex ( getState ( ) ) ;
389
+ if ( framebufIndex != null ) {
390
+ dispatch ( framebuf . actions . setName ( name , framebufIndex ) ) ;
391
+ }
392
+ }
393
+ }
394
+ }
395
+ }
331
396
) ( FramebufferTabs_ )
0 commit comments