@@ -55,6 +55,12 @@ const fadeIn = css.keyframes('fadeIn', {
5555 '100%' : { opacity : 1 } ,
5656} ) ;
5757
58+ const fadeOut = css . keyframes ( 'fadeOut' , {
59+ // optional name
60+ '0%' : { opacity : 1 } ,
61+ '100%' : { opacity : 0 } ,
62+ } ) ;
63+
5864function lineAndColumnToIndex ( lines , lineNumber , column ) {
5965 let currentLine = 0 ;
6066 let index = 0 ;
@@ -145,6 +151,10 @@ class MonacoEditor extends React.Component<Props, State> implements Editor {
145151
146152 this . resizeEditor = debounce ( this . resizeEditor , 500 ) ;
147153 this . commitLibChanges = debounce ( this . commitLibChanges , 300 ) ;
154+ this . onSelectionChangedDebounced = debounce (
155+ this . onSelectionChangedDebounced ,
156+ 500
157+ ) ;
148158 }
149159
150160 shouldComponentUpdate ( nextProps : Props ) {
@@ -270,36 +280,45 @@ class MonacoEditor extends React.Component<Props, State> implements Editor {
270280 } ) ;
271281
272282 editor . onDidChangeModelContent ( ( { changes } ) => {
273- const { isLive, sendTransforms, onCodeReceived } = this . props ;
283+ const { isLive, sendTransforms } = this . props ;
274284
275285 if ( isLive && sendTransforms && ! this . receivingCode ) {
276286 this . addChangesOperation ( changes ) ;
277287 }
278288 } ) ;
279289
280290 editor . onDidChangeCursorSelection ( selectionChange => {
291+ // TODO: add another debounced action to send the current data. So we can
292+ // have the correct cursor pos no matter what
281293 const { onSelectionChanged, isLive } = this . props ;
282294 // Reason 3 is update by mouse or arrow keys
283- if (
284- isLive &&
285- ( selectionChange . reason === 3 ||
286- /* alt + shift + arrow keys */ selectionChange . source ===
287- 'moveWordCommand' ||
288- /* click inside a selection */ selectionChange . source === 'api' ) &&
289- onSelectionChanged
290- ) {
295+ if ( isLive ) {
291296 const lines = editor . getModel ( ) . getLinesContent ( ) ;
292297 const data = {
293298 primary : getSelection ( lines , selectionChange . selection ) ,
294299 secondary : selectionChange . secondarySelections . map ( s =>
295300 getSelection ( lines , s )
296301 ) ,
297302 } ;
298-
299- onSelectionChanged ( {
300- selection : data ,
301- moduleShortid : this . currentModule . shortid ,
302- } ) ;
303+ if (
304+ ( selectionChange . reason === 3 ||
305+ /* alt + shift + arrow keys */ selectionChange . source ===
306+ 'moveWordCommand' ||
307+ /* click inside a selection */ selectionChange . source === 'api' ) &&
308+ onSelectionChanged
309+ ) {
310+ onSelectionChanged ( {
311+ selection : data ,
312+ moduleShortid : this . currentModule . shortid ,
313+ } ) ;
314+ } else {
315+ // This is just on typing, we send a debounced selection update as a
316+ // safeguard to make sure we are in sync
317+ this . onSelectionChangedDebounced ( {
318+ selection : data ,
319+ moduleShortid : this . currentModule . shortid ,
320+ } ) ;
321+ }
303322 }
304323 } ) ;
305324
@@ -390,6 +409,12 @@ class MonacoEditor extends React.Component<Props, State> implements Editor {
390409 } ) ;
391410 } ;
392411
412+ onSelectionChangedDebounced = data => {
413+ if ( this . props . onSelectionChanged ) {
414+ this . props . onSelectionChanged ( data ) ;
415+ }
416+ } ;
417+
393418 changes = { code : '' , changes : [ ] } ;
394419 changeTimeout : ?TimeoutID ;
395420 /**
@@ -519,30 +544,41 @@ class MonacoEditor extends React.Component<Props, State> implements Editor {
519544 const secondarySelectionClassName = userId + '-secondary-selection' ;
520545
521546 if ( ! this . userClassesGenerated [ cursorClassName ] ) {
547+ const nameStyles = {
548+ content : name ,
549+ position : 'absolute' ,
550+ top : - 17 ,
551+ backgroundColor : `rgb(${ color [ 0 ] } , ${ color [ 1 ] } , ${ color [ 2 ] } )` ,
552+ zIndex : 20 ,
553+ color :
554+ color [ 0 ] + color [ 1 ] + color [ 2 ] > 500
555+ ? 'rgba(0, 0, 0, 0.8)'
556+ : 'white' ,
557+ padding : '2px 4px' ,
558+ borderRadius : 2 ,
559+ borderBottomLeftRadius : 0 ,
560+ fontSize : '.75rem' ,
561+ fontWeight : 600 ,
562+ } ;
522563 this . userClassesGenerated [ cursorClassName ] = `${ css ( {
523564 backgroundColor : `rgba(${ color [ 0 ] } , ${ color [ 1 ] } , ${ color [ 2 ] } , 0.8)` ,
524565 width : '2px !important' ,
566+ marginLeft : - 1 ,
525567 cursor : 'text' ,
526568 zIndex : 30 ,
569+ ':before' : {
570+ animation : `${ fadeOut } 0.3s` ,
571+ animationDelay : '1s' ,
572+ animationFillMode : 'forwards' ,
573+ opacity : 1 ,
574+ ...nameStyles ,
575+ } ,
527576 ':hover' : {
528577 ':before' : {
529578 animation : `${ fadeIn } 0.3s` ,
530579 animationFillMode : 'forwards' ,
531580 opacity : 0 ,
532- content : name ,
533- position : 'absolute' ,
534- top : - 20 ,
535- backgroundColor : `rgb(${ color [ 0 ] } , ${ color [ 1 ] } , ${ color [ 2 ] } )` ,
536- zIndex : 20 ,
537- color :
538- color [ 0 ] + color [ 1 ] + color [ 2 ] > 500
539- ? 'rgba(0, 0, 0, 0.8)'
540- : 'white' ,
541- padding : '2px 6px' ,
542- borderRadius : 2 ,
543- borderBottomLeftRadius : 0 ,
544- fontSize : '.875rem' ,
545- fontWeight : 800 ,
581+ ...nameStyles ,
546582 } ,
547583 } ,
548584 } ) } `;
@@ -552,20 +588,23 @@ class MonacoEditor extends React.Component<Props, State> implements Editor {
552588 this . userClassesGenerated [ secondaryCursorClassName ] = `${ css ( {
553589 backgroundColor : `rgba(${ color [ 0 ] } , ${ color [ 1 ] } , ${ color [ 2 ] } , 0.6)` ,
554590 width : '2px !important' ,
591+ marginLeft : - 1 ,
555592 } ) } `;
556593 }
557594
558595 if ( ! this . userClassesGenerated [ selectionClassName ] ) {
559596 this . userClassesGenerated [ selectionClassName ] = `${ css ( {
560597 backgroundColor : `rgba(${ color [ 0 ] } , ${ color [ 1 ] } , ${ color [ 2 ] } , 0.3)` ,
561598 borderRadius : '3px' ,
599+ minWidth : 7.6 ,
562600 } ) } `;
563601 }
564602
565603 if ( ! this . userClassesGenerated [ secondarySelectionClassName ] ) {
566604 this . userClassesGenerated [ secondarySelectionClassName ] = `${ css ( {
567605 backgroundColor : `rgba(${ color [ 0 ] } , ${ color [ 1 ] } , ${ color [ 2 ] } , 0.2)` ,
568606 borderRadius : '3px' ,
607+ minWidth : 7.6 ,
569608 } ) } `;
570609 }
571610
0 commit comments