Don't blink cursors with CSS animation

It seems to create intermittent lags when moving the cursor and typing.
This commit is contained in:
Nathan Sobo
2014-05-20 14:04:59 -06:00
parent fa3ebc8c0f
commit 2ae7cba452
6 changed files with 39 additions and 41 deletions

View File

@@ -58,7 +58,7 @@
"temp": "0.5.0",
"text-buffer": "^2.2.2",
"theorist": "^1",
"underscore-plus": "^1.2.2",
"underscore-plus": "^1.3.0",
"vm-compatibility-layer": "0.1.0"
},
"packageDependencies": {

View File

@@ -1,4 +1,6 @@
{extend, flatten, toArray, last} = require 'underscore-plus'
_ = require 'underscore-plus'
{extend, flatten, toArray, last} = _
ReactEditorView = require '../src/react-editor-view'
nbsp = String.fromCharCode(160)
@@ -274,19 +276,22 @@ describe "EditorComponent", ->
expect(cursorRect.width).toBe rangeRect.width
it "blinks cursors when they aren't moving", ->
jasmine.unspy(window, 'setTimeout')
spyOn(_._, 'now').andCallFake -> window.now # Ensure _.debounce is based on our fake spec timeline
cursorsNode = node.querySelector('.cursors')
expect(cursorsNode.classList.contains('blinking')).toBe true
expect(cursorsNode.classList.contains('blink-off')).toBe false
advanceClock(component.props.cursorBlinkPeriod / 2)
expect(cursorsNode.classList.contains('blink-off')).toBe true
advanceClock(component.props.cursorBlinkPeriod / 2)
expect(cursorsNode.classList.contains('blink-off')).toBe false
# Stop blinking after moving the cursor
editor.moveCursorRight()
expect(cursorsNode.classList.contains('blinking')).toBe false
expect(cursorsNode.classList.contains('blink-off')).toBe false
# Resume blinking after resume delay passes
waits component.props.cursorBlinkResumeDelay
runs ->
expect(cursorsNode.classList.contains('blinking')).toBe true
advanceClock(component.props.cursorBlinkResumeDelay)
advanceClock(component.props.cursorBlinkPeriod / 2)
expect(cursorsNode.classList.contains('blink-off')).toBe true
it "renders the hidden input field at the position of the last cursor if it is on screen", ->
inputNode = node.querySelector('.hidden-input')

View File

@@ -13,10 +13,10 @@ CursorsComponent = React.createClass
render: ->
{editor, scrollTop, scrollLeft} = @props
{blinking} = @state
{blinkOff} = @state
className = 'cursors'
className += ' blinking' if blinking
className += ' blink-off' if blinkOff
div {className},
if @isMounted()
@@ -26,32 +26,32 @@ CursorsComponent = React.createClass
CursorComponent({key: cursor.id, cursor, scrollTop, scrollLeft})
getInitialState: ->
blinking: true
blinkOff: false
componentDidMount: ->
{editor} = @props
@startBlinkingCursors()
componentWillUnmount: ->
clearInterval(@cursorBlinkIntervalHandle)
@stopBlinkingCursors()
componentWillUpdate: ({cursorsMoved}) ->
@pauseCursorBlinking() if cursorsMoved
componentDidUpdate: ->
@syncCursorAnimations() if @props.selectionAdded
startBlinkingCursors: ->
@setState(blinking: true) if @isMounted()
@toggleCursorBlinkHandle = setInterval(@toggleCursorBlink, @props.cursorBlinkPeriod / 2) if @isMounted()
startBlinkingCursorsAfterDelay: null # Created lazily
stopBlinkingCursors: ->
console.log "START"
clearInterval(@toggleCursorBlinkHandle)
toggleCursorBlink: ->
console.log "TOGGLE"
@setState(blinkOff: not @state.blinkOff)
pauseCursorBlinking: ->
@state.blinking = false
@state.blinkOff = false
@stopBlinkingCursors()
@startBlinkingCursorsAfterDelay ?= debounce(@startBlinkingCursors, @props.cursorBlinkResumeDelay)
@startBlinkingCursorsAfterDelay()
syncCursorAnimations: ->
node = @getDOMNode()
cursorNodes = toArray(node.children)
node.removeChild(cursorNode) for cursorNode in cursorNodes
node.appendChild(cursorNode) for cursorNode in cursorNodes

View File

@@ -32,7 +32,7 @@ EditorComponent = React.createClass
render: ->
{focused, fontSize, lineHeight, fontFamily, showIndentGuide} = @state
{editor, cursorBlinkResumeDelay} = @props
{editor, cursorBlinkPeriod, cursorBlinkResumeDelay} = @props
maxLineNumberDigits = editor.getScreenLineCount().toString().length
if @isMounted()
@@ -61,8 +61,8 @@ EditorComponent = React.createClass
ref: 'scrollView', editor, fontSize, fontFamily, showIndentGuide,
lineHeight: lineHeightInPixels, renderedRowRange, @pendingChanges,
scrollTop, scrollLeft, scrollHeight, scrollWidth, @scrollingVertically,
@cursorsMoved, @selectionChanged, @selectionAdded, cursorBlinkResumeDelay,
@onInputFocused, @onInputBlurred, @mouseWheelScreenRow
@cursorsMoved, @selectionChanged, @selectionAdded, cursorBlinkPeriod,
cursorBlinkResumeDelay, @onInputFocused, @onInputBlurred, @mouseWheelScreenRow
}
ScrollbarComponent
@@ -107,6 +107,7 @@ EditorComponent = React.createClass
getInitialState: -> {}
getDefaultProps: ->
cursorBlinkPeriod: 800
cursorBlinkResumeDelay: 100
lineOverdrawMargin: 8

View File

@@ -18,7 +18,7 @@ EditorScrollViewComponent = React.createClass
render: ->
{editor, fontSize, fontFamily, lineHeight, showIndentGuide} = @props
{renderedRowRange, pendingChanges, scrollTop, scrollLeft, scrollHeight, scrollWidth, scrollingVertically, mouseWheelScreenRow} = @props
{selectionChanged, selectionAdded, cursorBlinkResumeDelay, cursorsMoved, onInputFocused, onInputBlurred} = @props
{selectionChanged, selectionAdded, cursorBlinkPeriod, cursorBlinkResumeDelay, cursorsMoved, onInputFocused, onInputBlurred} = @props
if @isMounted()
inputStyle = @getHiddenInputPosition()
@@ -33,7 +33,7 @@ EditorScrollViewComponent = React.createClass
onFocus: onInputFocused
onBlur: onInputBlurred
CursorsComponent({editor, scrollTop, scrollLeft, cursorsMoved, selectionAdded, cursorBlinkResumeDelay})
CursorsComponent({editor, scrollTop, scrollLeft, cursorsMoved, selectionAdded, cursorBlinkPeriod, cursorBlinkResumeDelay})
LinesComponent {
ref: 'lines', editor, fontSize, fontFamily, lineHeight, showIndentGuide,
renderedRowRange, pendingChanges, scrollTop, scrollLeft, scrollingVertically,

View File

@@ -20,16 +20,8 @@
z-index: 1;
}
&.is-focused .cursors.blinking .cursor {
-webkit-animation: blink 0.8s;
-webkit-animation-iteration-count: infinite;
}
@-webkit-keyframes blink {
0% { opacity: .7; }
50% { opacity: .7; }
51% { opacity: 0; }
100% { opacity: 0; }
&.is-focused .cursors.blink-off .cursor {
visibility: hidden;
}
.horizontal-scrollbar {