1
1
import { TranslationBundle } from '@jupyterlab/translation' ;
2
+ import { checkIcon } from '@jupyterlab/ui-components' ;
2
3
import { CommandRegistry } from '@lumino/commands' ;
4
+ import Button from '@material-ui/core/Button' ;
5
+ import ButtonGroup from '@material-ui/core/ButtonGroup' ;
6
+ import ClickAwayListener from '@material-ui/core/ClickAwayListener' ;
7
+ import Grow from '@material-ui/core/Grow' ;
8
+ import MenuItem from '@material-ui/core/MenuItem' ;
9
+ import MenuList from '@material-ui/core/MenuList' ;
10
+ import Paper from '@material-ui/core/Paper' ;
11
+ import Popper from '@material-ui/core/Popper' ;
3
12
import * as React from 'react' ;
4
- import TextareaAutosize from 'react-textarea-autosize' ;
13
+ import { classes } from 'typestyle' ;
14
+ import { listItemIconClass } from '../style/BranchMenu' ;
5
15
import {
6
16
commitButtonClass ,
7
- commitDescriptionClass ,
8
17
commitFormClass ,
9
- commitSummaryClass ,
10
- commitInputWrapperClass
18
+ commitPaperClass ,
19
+ commitRoot ,
20
+ commitVariantSelector ,
21
+ disabledStyle
11
22
} from '../style/CommitBox' ;
23
+ import { verticalMoreIcon } from '../style/icons' ;
24
+ import {
25
+ listItemBoldTitleClass ,
26
+ listItemContentClass ,
27
+ listItemDescClass
28
+ } from '../style/NewBranchDialog' ;
12
29
import { CommandIDs } from '../tokens' ;
30
+ import { CommitMessage } from './CommitMessage' ;
31
+
32
+ /**
33
+ * Commit action
34
+ */
35
+ interface ICommitVariant {
36
+ /**
37
+ * Action title
38
+ */
39
+ title : string ;
40
+ /**
41
+ * Action description
42
+ */
43
+ description : string ;
44
+ }
13
45
14
46
/**
15
47
* Interface describing component properties.
@@ -46,7 +78,7 @@ export interface ICommitBoxProps {
46
78
description : string ;
47
79
48
80
/**
49
- * Whether the "amend" checkbox is checked
81
+ * Whether commit is amending the previous one or not
50
82
*/
51
83
amend : boolean ;
52
84
@@ -79,10 +111,23 @@ export interface ICommitBoxProps {
79
111
onCommit : ( ) => Promise < void > ;
80
112
}
81
113
114
+ /**
115
+ * CommitBox state
116
+ */
117
+ export interface ICommitBoxState {
118
+ /**
119
+ * Whether the commit variant menu is opened or not.
120
+ */
121
+ open : boolean ;
122
+ }
123
+
82
124
/**
83
125
* React component for entering a commit message.
84
126
*/
85
- export class CommitBox extends React . Component < ICommitBoxProps > {
127
+ export class CommitBox extends React . Component <
128
+ ICommitBoxProps ,
129
+ ICommitBoxState
130
+ > {
86
131
/**
87
132
* Returns a React component for entering a commit message.
88
133
*
@@ -91,6 +136,25 @@ export class CommitBox extends React.Component<ICommitBoxProps> {
91
136
*/
92
137
constructor ( props : ICommitBoxProps ) {
93
138
super ( props ) ;
139
+ this . _options . push (
140
+ {
141
+ title : this . props . trans . __ ( 'Create a new commit' ) ,
142
+ description : this . props . trans . __ (
143
+ 'New commit will be created and show up as a next one after the previous commit (default).'
144
+ )
145
+ } ,
146
+ {
147
+ title : this . props . trans . __ ( 'Amend previous commit' ) ,
148
+ description : this . props . trans . __ (
149
+ 'Staged changes will be added to the previous commit and its date will be updated.'
150
+ )
151
+ }
152
+ ) ;
153
+ this . _anchorRef = React . createRef < HTMLDivElement > ( ) ;
154
+
155
+ this . state = {
156
+ open : false
157
+ } ;
94
158
}
95
159
96
160
componentDidMount ( ) : void {
@@ -122,58 +186,92 @@ export class CommitBox extends React.Component<ICommitBoxProps> {
122
186
shortcutHint
123
187
) ;
124
188
return (
125
- < form className = { [ commitFormClass , 'jp-git-CommitBox' ] . join ( ' ' ) } >
126
- < input
127
- className = { commitSummaryClass }
128
- type = "text"
129
- placeholder = { summaryPlaceholder }
130
- title = {
131
- this . props . amend
132
- ? this . props . trans . __ (
133
- 'Amending the commit will re-use the previous commit summary'
134
- )
135
- : this . props . trans . __ (
136
- 'Enter a commit message summary (a single line, preferably less than 50 characters)'
137
- )
138
- }
139
- value = { this . props . summary }
140
- onChange = { this . _onSummaryChange }
141
- onKeyPress = { this . _onSummaryKeyPress }
189
+ < div className = { classes ( commitFormClass , 'jp-git-CommitBox' ) } >
190
+ < CommitMessage
191
+ trans = { this . props . trans }
192
+ summary = { this . props . summary }
193
+ summaryPlaceholder = { summaryPlaceholder }
194
+ description = { this . props . description }
142
195
disabled = { this . props . amend }
196
+ setSummary = { this . props . setSummary }
197
+ setDescription = { this . props . setDescription }
143
198
/>
144
- < TextareaAutosize
145
- className = { commitDescriptionClass }
146
- minRows = { 5 }
147
- placeholder = { this . props . trans . __ ( 'Description (optional)' ) }
148
- title = {
149
- this . props . amend
150
- ? this . props . trans . __ (
151
- 'Amending the commit will re-use the previous commit summary'
152
- )
153
- : this . props . trans . __ ( 'Enter a commit message description' )
154
- }
155
- value = { this . props . description }
156
- onChange = { this . _onDescriptionChange }
157
- disabled = { this . props . amend }
158
- />
159
- < div className = { commitInputWrapperClass } >
160
- < input
161
- className = { commitButtonClass }
162
- type = "button"
199
+ < ButtonGroup ref = { this . _anchorRef } fullWidth = { true } size = "small" >
200
+ < Button
201
+ classes = { {
202
+ root : commitButtonClass ,
203
+ disabled : disabledStyle
204
+ } }
163
205
title = { title }
164
- value = { this . props . label }
165
206
disabled = { disabled }
166
207
onClick = { this . props . onCommit }
167
- />
168
- < input
169
- type = "checkbox"
170
- id = "commit-amend"
171
- onChange = { this . _onAmendChange }
172
- checked = { this . props . amend }
173
- />
174
- < label htmlFor = "commit-amend" > Amend</ label >
175
- </ div >
176
- </ form >
208
+ >
209
+ { this . props . label }
210
+ </ Button >
211
+ < Button
212
+ classes = { {
213
+ root : commitButtonClass
214
+ } }
215
+ className = { commitVariantSelector }
216
+ size = "small"
217
+ aria-controls = { this . state . open ? 'split-button-menu' : undefined }
218
+ aria-expanded = { this . state . open ? 'true' : undefined }
219
+ aria-label = "select commit variant"
220
+ aria-haspopup = "menu"
221
+ onClick = { this . _handleToggle }
222
+ >
223
+ < verticalMoreIcon . react tag = "span" />
224
+ </ Button >
225
+ </ ButtonGroup >
226
+ < Popper
227
+ open = { this . state . open }
228
+ anchorEl = { this . _anchorRef . current }
229
+ role = { undefined }
230
+ transition
231
+ disablePortal
232
+ >
233
+ { ( { TransitionProps } ) => (
234
+ < Grow { ...TransitionProps } >
235
+ < Paper
236
+ classes = { { root : commitRoot } }
237
+ className = { commitPaperClass }
238
+ >
239
+ < ClickAwayListener onClickAway = { this . _handleClose } >
240
+ < MenuList id = "split-button-menu" >
241
+ { this . _options . map ( ( option , index ) => (
242
+ < MenuItem
243
+ key = { option . title }
244
+ classes = { { root : commitRoot } }
245
+ selected = { this . props . amend ? index === 1 : index === 0 }
246
+ onClick = { event =>
247
+ this . _handleMenuItemClick ( event , index )
248
+ }
249
+ >
250
+ { ( this . props . amend ? index === 1 : index === 0 ) ? (
251
+ < checkIcon . react
252
+ className = { listItemIconClass }
253
+ tag = "span"
254
+ />
255
+ ) : (
256
+ < span className = { listItemIconClass } />
257
+ ) }
258
+ < div className = { listItemContentClass } >
259
+ < p className = { listItemBoldTitleClass } >
260
+ { option . title }
261
+ </ p >
262
+ < p className = { listItemDescClass } >
263
+ { option . description }
264
+ </ p >
265
+ </ div >
266
+ </ MenuItem >
267
+ ) ) }
268
+ </ MenuList >
269
+ </ ClickAwayListener >
270
+ </ Paper >
271
+ </ Grow >
272
+ ) }
273
+ </ Popper >
274
+ </ div >
177
275
) ;
178
276
}
179
277
@@ -198,45 +296,39 @@ export class CommitBox extends React.Component<ICommitBoxProps> {
198
296
} ;
199
297
200
298
/**
201
- * Callback invoked upon updating a commit message description.
202
- *
203
- * @param event - event object
299
+ * Close the commit variant menu if needed.
204
300
*/
205
- private _onDescriptionChange = ( event : any ) : void => {
206
- this . props . setDescription ( event . target . value ) ;
207
- } ;
301
+ private _handleClose = (
302
+ event : React . MouseEvent < Document , MouseEvent >
303
+ ) : void => {
304
+ if (
305
+ this . _anchorRef . current &&
306
+ this . _anchorRef . current . contains ( event . target as HTMLElement )
307
+ ) {
308
+ return ;
309
+ }
208
310
209
- /**
210
- * Callback invoked upon updating a commit message summary.
211
- *
212
- * @param event - event object
213
- */
214
- private _onSummaryChange = ( event : any ) : void => {
215
- this . props . setSummary ( event . target . value ) ;
311
+ this . setState ( { open : false } ) ;
216
312
} ;
217
313
218
314
/**
219
- * Callback invoked when the amend checkbox is toggled
220
- *
221
- * @param event - event object
315
+ * Handle commit variant menu item click
222
316
*/
223
- private _onAmendChange = ( event : any ) : void => {
224
- this . props . setAmend ( event . target . checked ) ;
317
+ private _handleMenuItemClick = (
318
+ event : React . MouseEvent < HTMLLIElement , MouseEvent > ,
319
+ index : number
320
+ ) : void => {
321
+ this . setState ( {
322
+ open : false
323
+ } ) ;
324
+ this . props . setAmend ( index === 1 ) ;
225
325
} ;
226
326
227
327
/**
228
- * Callback invoked upon a `'keypress'` event when entering a commit message summary.
229
- *
230
- * ## Notes
231
- *
232
- * - Prevents triggering a `'submit'` action when hitting the `ENTER` key while entering a commit message summary.
233
- *
234
- * @param event - event object
328
+ * Toggle state of the commit variant menu visibility
235
329
*/
236
- private _onSummaryKeyPress = ( event : React . KeyboardEvent ) : void => {
237
- if ( event . key === 'Enter' ) {
238
- event . preventDefault ( ) ;
239
- }
330
+ private _handleToggle = ( ) : void => {
331
+ this . setState ( { open : ! this . state . open } ) ;
240
332
} ;
241
333
242
334
/**
@@ -255,4 +347,7 @@ export class CommitBox extends React.Component<ICommitBoxProps> {
255
347
this . props . onCommit ( ) ;
256
348
}
257
349
} ;
350
+
351
+ private _anchorRef : React . RefObject < HTMLDivElement > ;
352
+ private _options : ICommitVariant [ ] = [ ] ;
258
353
}
0 commit comments