Merge pull request #3943 from atom/ns-text-editor-shadow-dom

Render text editor contents inside shadow DOM
This commit is contained in:
Nathan Sobo
2014-11-05 09:42:07 -07:00
31 changed files with 667 additions and 474 deletions

View File

@@ -109,6 +109,11 @@ module.exports =
type: 'boolean'
default: true
description: 'Disabling will improve editor font rendering but reduce scrolling performance.'
useShadowDOM:
type: 'boolean'
default: false
title: 'Use Shadow DOM'
description: 'Enable to test out themes and packages with the new shadow DOM before it ships by default.'
confirmCheckoutHeadRevision:
type: 'boolean'
default: true

View File

@@ -16,12 +16,12 @@ GutterComponent = React.createClass
measuredWidth: null
render: ->
{scrollHeight, scrollViewHeight, onMouseDown, backgroundColor, gutterBackgroundColor} = @props
{scrollHeight, scrollViewHeight, backgroundColor, gutterBackgroundColor} = @props
if gutterBackgroundColor isnt 'rbga(0, 0, 0, 0)'
backgroundColor = gutterBackgroundColor
div className: 'gutter', onClick: @onClick, onMouseDown: @onMouseDown,
div className: 'gutter',
div className: 'line-numbers', ref: 'lineNumbers', style:
height: Math.max(scrollHeight, scrollViewHeight)
WebkitTransform: @getTransform()
@@ -45,6 +45,10 @@ GutterComponent = React.createClass
@appendDummyLineNumber()
@updateLineNumbers() if @props.performedInitialMeasurement
node = @getDOMNode()
node.addEventListener 'click', @onClick
node.addEventListener 'mousedown', @onMouseDown
# Only update the gutter if the visible row range has changed or if a
# non-zero-delta change to the screen lines has occurred within the current
# visible row range.

View File

@@ -21,5 +21,11 @@ HighlightsComponent = React.createClass
highlightComponents
componentDidMount: ->
if atom.config.get('editor.useShadowDOM')
insertionPoint = document.createElement('content')
insertionPoint.setAttribute('select', '.underlayer')
@getDOMNode().appendChild(insertionPoint)
shouldComponentUpdate: (newProps) ->
not isEqualForProperties(newProps, @props, 'highlightDecorations', 'lineHeightInPixels', 'defaultCharWidth', 'scopedCharacterWidthsChangeCount')

View File

@@ -7,16 +7,17 @@ InputComponent = React.createClass
displayName: 'InputComponent'
render: ->
{className, style, onFocus, onBlur} = @props
{className, style} = @props
input {className, style, onFocus, onBlur, 'data-react-skip-selection-restoration': true}
input {className, style, 'data-react-skip-selection-restoration': true}
getInitialState: ->
{lastChar: ''}
componentDidMount: ->
@getDOMNode().addEventListener 'paste', @onPaste
@getDOMNode().addEventListener 'compositionupdate', @onCompositionUpdate
node = @getDOMNode()
node.addEventListener 'paste', @onPaste
node.addEventListener 'compositionupdate', @onCompositionUpdate
# Don't let text accumulate in the input forever, but avoid excessive reflows
componentDidUpdate: ->
@@ -34,11 +35,5 @@ InputComponent = React.createClass
onPaste: (e) ->
e.preventDefault()
onFocus: ->
@props.onFocus?()
onBlur: ->
@props.onBlur?()
focus: ->
@getDOMNode().focus()

View File

@@ -57,6 +57,12 @@ LinesComponent = React.createClass
@lineIdsByScreenRow = {}
@renderedDecorationsByLineId = {}
componentDidMount: ->
if atom.config.get('editor.useShadowDOM')
insertionPoint = document.createElement('content')
insertionPoint.setAttribute('select', '.overlayer')
@getDOMNode().appendChild(insertionPoint)
shouldComponentUpdate: (newProps) ->
return true unless isEqualForProperties(newProps, @props,
'renderedRowRange', 'lineDecorations', 'highlightDecorations', 'lineHeightInPixels', 'defaultCharWidth',

View File

@@ -50,6 +50,7 @@ class Package
keymaps: null
menus: null
stylesheets: null
stylesheetDisposables: null
grammars: null
scopedProperties: null
mainModulePath: null
@@ -175,9 +176,16 @@ class Package
activateStylesheets: ->
return if @stylesheetsActivated
type = @getStylesheetType()
for [stylesheetPath, content] in @stylesheets
atom.themes.applyStylesheet(stylesheetPath, content, type)
group = @getStylesheetType()
@stylesheetDisposables = new CompositeDisposable
for [sourcePath, source] in @stylesheets
if match = path.basename(sourcePath).match(/[^.]*\.([^.]*)\./)
context = match[1]
else if @metadata.theme is 'syntax'
context = 'atom-text-editor'
@stylesheetDisposables.add(atom.styles.addStyleSheet(source, {sourcePath, group, context}))
@stylesheetsActivated = true
activateResources: ->
@@ -320,7 +328,7 @@ class Package
deactivateResources: ->
grammar.deactivate() for grammar in @grammars
scopedProperties.deactivate() for scopedProperties in @scopedProperties
atom.themes.removeStylesheet(stylesheetPath) for [stylesheetPath] in @stylesheets
@stylesheetDisposables?.dispose()
@activationDisposables?.dispose()
@stylesheetsActivated = false
@grammarsActivated = false
@@ -329,11 +337,10 @@ class Package
reloadStylesheets: ->
oldSheets = _.clone(@stylesheets)
@loadStylesheets()
atom.themes.removeStylesheet(stylesheetPath) for [stylesheetPath] in oldSheets
@reloadStylesheet(stylesheetPath, content) for [stylesheetPath, content] in @stylesheets
reloadStylesheet: (stylesheetPath, content) ->
atom.themes.applyStylesheet(stylesheetPath, content, @getStylesheetType())
@stylesheetDisposables.dispose()
@stylesheetDisposables = new CompositeDisposable
@stylesheetsActivated = false
@activateStylesheets()
requireMainModule: ->
return @mainModule if @mainModule?

View File

@@ -28,9 +28,17 @@ class PaneElement extends HTMLElement
@itemViews.setAttribute 'class', 'item-views'
subscribeToDOMEvents: ->
@addEventListener 'focusin', => @model.focus()
@addEventListener 'focusout', => @model.blur()
@addEventListener 'focus', => @getActiveView()?.focus()
handleFocus = (event) =>
@model.focus()
if event.target is this and view = @getActiveView()
view.focus()
event.stopPropagation()
handleBlur = (event) =>
@model.blur() unless @contains(event.relatedTarget)
@addEventListener 'focus', handleFocus, true
@addEventListener 'blur', handleBlur, true
createSpacePenShim: ->
@__spacePenView = new PaneView(this)

View File

@@ -23,7 +23,7 @@ ScrollbarComponent = React.createClass
style.right = verticalScrollbarWidth if scrollableInOppositeDirection
style.height = horizontalScrollbarHeight
div {className, style, @onScroll},
div {className, style},
switch orientation
when 'vertical'
div className: 'scrollbar-content', style: {height: scrollHeight}
@@ -36,6 +36,11 @@ ScrollbarComponent = React.createClass
unless orientation is 'vertical' or orientation is 'horizontal'
throw new Error("Must specify an orientation property of 'vertical' or 'horizontal'")
@getDOMNode().addEventListener 'scroll', @onScroll
componentWillUnmount: ->
@getDOMNode().removeEventListener 'scroll', @onScroll
shouldComponentUpdate: (newProps) ->
return true if newProps.visible isnt @props.visible

View File

@@ -57,7 +57,7 @@ class SelectListView extends View
initialize: ->
@filterEditorView.getEditor().getBuffer().onDidChange =>
@schedulePopulateList()
@filterEditorView.hiddenInput.on 'focusout', =>
@filterEditorView.on 'blur', =>
@cancel() unless @cancelling
# This prevents the focusout event from firing on the filter editor view
@@ -254,7 +254,7 @@ class SelectListView extends View
# Extended: Store the currently focused element. This element will be given
# back focus when {::cancel} is called.
storeFocusedElement: ->
@previouslyFocusedElement = $(':focus')
@previouslyFocusedElement = $(document.activeElement)
###
Section: Private

View File

@@ -81,6 +81,18 @@ jQuery.event.remove = (elem, types, originalHandler, selector, mappedTypes) ->
handler = HandlersByOriginalHandler.get(originalHandler) ? originalHandler
JQueryEventRemove(elem, types, handler, selector, mappedTypes, RemoveEventListener if atom?.commands?)
JQueryContains = jQuery.contains
jQuery.contains = (a, b) ->
shadowRoot = null
currentNode = b
while currentNode
if currentNode instanceof ShadowRoot and a.contains(currentNode.host)
return true
currentNode = currentNode.parentNode
JQueryContains.call(this, a, b)
tooltipDefaults =
delay:
show: 1000

View File

@@ -25,6 +25,7 @@ class StyleManager
addStyleSheet: (source, params) ->
sourcePath = params?.sourcePath
context = params?.context
group = params?.group
if sourcePath? and styleElement = @styleElementsBySourcePath[sourcePath]

View File

@@ -1,8 +1,8 @@
{Emitter, CompositeDisposable} = require 'event-kit'
class StylesElement extends HTMLElement
createdCallback: ->
@emitter = new Emitter
subscriptions: null
context: null
onDidAddStyleElement: (callback) ->
@emitter.on 'did-add-style-element', callback
@@ -13,15 +13,42 @@ class StylesElement extends HTMLElement
onDidUpdateStyleElement: (callback) ->
@emitter.on 'did-update-style-element', callback
attachedCallback: ->
@subscriptions = new CompositeDisposable
createdCallback: ->
@emitter = new Emitter
@styleElementClonesByOriginalElement = new WeakMap
attachedCallback: ->
@initialize()
detachedCallback: ->
@subscriptions.dispose()
@subscriptions = null
attributeChangedCallback: (attrName, oldVal, newVal) ->
@contextChanged() if attrName is 'context'
initialize: ->
return if @subscriptions?
@subscriptions = new CompositeDisposable
@context = @getAttribute('context') ? undefined
@subscriptions.add atom.styles.observeStyleElements(@styleElementAdded.bind(this))
@subscriptions.add atom.styles.onDidRemoveStyleElement(@styleElementRemoved.bind(this))
@subscriptions.add atom.styles.onDidUpdateStyleElement(@styleElementUpdated.bind(this))
contextChanged: ->
return unless @subscriptions?
@styleElementRemoved(child) for child in Array::slice.call(@children)
@context = @getAttribute('context')
@styleElementAdded(styleElement) for styleElement in atom.styles.getStyleElements()
styleElementAdded: (styleElement) ->
return unless styleElement.context is @context
styleElementClone = styleElement.cloneNode(true)
styleElementClone.context = styleElement.context
@styleElementClonesByOriginalElement.set(styleElement, styleElementClone)
group = styleElement.getAttribute('group')
@@ -35,16 +62,17 @@ class StylesElement extends HTMLElement
@emitter.emit 'did-add-style-element', styleElementClone
styleElementRemoved: (styleElement) ->
styleElementClone = @styleElementClonesByOriginalElement.get(styleElement)
return unless styleElement.context is @context
styleElementClone = @styleElementClonesByOriginalElement.get(styleElement) ? styleElement
styleElementClone.remove()
@emitter.emit 'did-remove-style-element', styleElementClone
styleElementUpdated: (styleElement) ->
return unless styleElement.context is @context
styleElementClone = @styleElementClonesByOriginalElement.get(styleElement)
styleElementClone.textContent = styleElement.textContent
@emitter.emit 'did-update-style-element', styleElementClone
detachedCallback: ->
@subscriptions.dispose()
module.exports = StylesElement = document.registerElement 'atom-styles', prototype: StylesElement.prototype

View File

@@ -93,7 +93,7 @@ TextEditorComponent = React.createClass
className += ' is-focused' if focused
className += ' has-selection' if hasSelection
div {className, style, tabIndex: -1},
div {className, style},
if @shouldRenderGutter()
GutterComponent {
ref: 'gutter', onMouseDown: @onGutterMouseDown, lineDecorations,
@@ -102,13 +102,11 @@ TextEditorComponent = React.createClass
@useHardwareAcceleration, @performedInitialMeasurement, @backgroundColor, @gutterBackgroundColor
}
div ref: 'scrollView', className: 'scroll-view', onMouseDown: @onMouseDown,
div ref: 'scrollView', className: 'scroll-view',
InputComponent
ref: 'input'
className: 'hidden-input'
style: hiddenInputStyle
onFocus: @onInputFocused
onBlur: @onInputBlurred
LinesComponent {
ref: 'lines',
@@ -175,14 +173,14 @@ TextEditorComponent = React.createClass
@setScrollSensitivity(atom.config.get('editor.scrollSensitivity'))
componentDidMount: ->
{editor} = @props
{editor, stylesElement} = @props
@observeEditor()
@listenForDOMEvents()
@subscribe atom.themes.onDidAddStylesheet @onStylesheetsChanged
@subscribe atom.themes.onDidUpdateStylesheet @onStylesheetsChanged
@subscribe atom.themes.onDidRemoveStylesheet @onStylesheetsChanged
@subscribe stylesElement.onDidAddStyleElement @onStylesheetsChanged
@subscribe stylesElement.onDidUpdateStyleElement @onStylesheetsChanged
@subscribe stylesElement.onDidRemoveStyleElement @onStylesheetsChanged
unless atom.themes.isInitialLoadComplete()
@subscribe atom.themes.onDidReloadAll @onStylesheetsChanged
@subscribe scrollbarStyle.changes, @refreshScrollbars
@@ -193,9 +191,9 @@ TextEditorComponent = React.createClass
@checkForVisibilityChange()
componentWillUnmount: ->
{editor, parentView} = @props
{editor, hostElement} = @props
parentView.__spacePenView.trigger 'editor:will-be-removed', [parentView.__spacePenView]
hostElement.__spacePenView.trigger 'editor:will-be-removed', [hostElement.__spacePenView]
@unsubscribe()
@scopedConfigSubscriptions.dispose()
window.removeEventListener 'resize', @requestHeightAndWidthMeasurement
@@ -215,9 +213,9 @@ TextEditorComponent = React.createClass
if @props.editor.isAlive()
@updateParentViewFocusedClassIfNeeded(prevState)
@updateParentViewMiniClassIfNeeded(prevState)
@props.parentView.__spacePenView.trigger 'cursor:moved' if cursorMoved
@props.parentView.__spacePenView.trigger 'selection:changed' if selectionChanged
@props.parentView.__spacePenView.trigger 'editor:display-updated'
@props.hostElement.__spacePenView.trigger 'cursor:moved' if cursorMoved
@props.hostElement.__spacePenView.trigger 'selection:changed' if selectionChanged
@props.hostElement.__spacePenView.trigger 'editor:display-updated'
becameVisible: ->
@updatesPaused = true
@@ -261,7 +259,7 @@ TextEditorComponent = React.createClass
@forceUpdate()
getTopmostDOMNode: ->
@props.parentView
@props.hostElement
getRenderedRowRange: ->
{editor, lineOverdrawMargin} = @props
@@ -378,8 +376,8 @@ TextEditorComponent = React.createClass
listenForDOMEvents: ->
node = @getDOMNode()
node.addEventListener 'mousewheel', @onMouseWheel
node.addEventListener 'focus', @onFocus # For some reason, React's built in focus events seem to bubble
node.addEventListener 'textInput', @onTextInput
@refs.scrollView.getDOMNode().addEventListener 'mousedown', @onMouseDown
scrollViewNode = @refs.scrollView.getDOMNode()
scrollViewNode.addEventListener 'scroll', @onScrollViewScroll
@@ -415,6 +413,9 @@ TextEditorComponent = React.createClass
observeConfig: ->
@subscribe atom.config.observe 'editor.useHardwareAcceleration', @setUseHardwareAcceleration
@subscribe atom.config.onDidChange 'editor.fontSize', @sampleFontStyling
@subscribe atom.config.onDidChange 'editor.fontFamily', @sampleFontStyling
@subscribe atom.config.onDidChange 'editor.lineHeight', @sampleFontStyling
onGrammarChanged: ->
{editor} = @props
@@ -428,8 +429,14 @@ TextEditorComponent = React.createClass
subscriptions.add atom.config.observe scopeDescriptor, 'editor.showLineNumbers', @setShowLineNumbers
subscriptions.add atom.config.observe scopeDescriptor, 'editor.scrollSensitivity', @setScrollSensitivity
onFocus: ->
@refs.input.focus() if @isMounted()
focused: ->
if @isMounted()
@setState(focused: true)
@refs.input.focus()
blurred: ->
if @isMounted()
@setState(focused: false)
onTextInput: (event) ->
event.stopPropagation()
@@ -452,12 +459,6 @@ TextEditorComponent = React.createClass
inputNode.value = event.data if editor.insertText(event.data)
onInputFocused: ->
@setState(focused: true)
onInputBlurred: ->
@setState(focused: false)
onVerticalScroll: (scrollTop) ->
{editor} = @props
@@ -621,11 +622,11 @@ TextEditorComponent = React.createClass
else
editor.setSelectedScreenRange([tailPosition, [dragRow + 1, 0]], preserveFolds: true)
onStylesheetsChanged: (stylesheet) ->
onStylesheetsChanged: (styleElement) ->
return unless @performedInitialMeasurement
return unless atom.themes.isInitialLoadComplete()
@refreshScrollbars() if not stylesheet? or @containsScrollbarSelector(stylesheet)
@refreshScrollbars() if not styleElement.sheet? or @containsScrollbarSelector(styleElement.sheet)
@sampleFontStyling()
@sampleBackgroundColors()
@remeasureCharacterWidths()
@@ -771,10 +772,10 @@ TextEditorComponent = React.createClass
measureHeightAndWidth: ->
return unless @isMounted()
{editor, parentView} = @props
{editor, hostElement} = @props
scrollViewNode = @refs.scrollView.getDOMNode()
{position} = getComputedStyle(parentView)
{height} = parentView.style
{position} = getComputedStyle(hostElement)
{height} = hostElement.style
if position is 'absolute' or height
if @autoHeight
@@ -806,9 +807,9 @@ TextEditorComponent = React.createClass
@remeasureCharacterWidths()
sampleBackgroundColors: (suppressUpdate) ->
{parentView} = @props
{hostElement} = @props
{showLineNumbers} = @state
{backgroundColor} = getComputedStyle(parentView)
{backgroundColor} = getComputedStyle(hostElement)
if backgroundColor isnt @backgroundColor
@backgroundColor = backgroundColor
@@ -907,10 +908,10 @@ TextEditorComponent = React.createClass
lineNumberNodeForScreenRow: (screenRow) -> @refs.gutter.lineNumberNodeForScreenRow(screenRow)
screenRowForNode: (node) ->
while node isnt document
while node?
if screenRow = node.dataset.screenRow
return parseInt(screenRow)
node = node.parentNode
node = node.parentElement
null
getFontSize: ->
@@ -977,11 +978,13 @@ TextEditorComponent = React.createClass
updateParentViewFocusedClassIfNeeded: (prevState) ->
if prevState.focused isnt @state.focused
@props.parentView.classList.toggle('is-focused', @state.focused)
@props.hostElement.classList.toggle('is-focused', @state.focused)
@props.rootElement.classList.toggle('is-focused', @state.focused)
updateParentViewMiniClassIfNeeded: (prevProps) ->
if prevProps.mini isnt @props.mini
@props.parentView.classList.toggle('mini', @props.mini)
@props.hostElement.classList.toggle('mini', @props.mini)
@props.rootElement.classList.toggle('mini', @props.mini)
runScrollBenchmark: ->
unless process.env.NODE_ENV is 'production'

View File

@@ -6,6 +6,8 @@ TextEditor = require './text-editor'
TextEditorComponent = require './text-editor-component'
TextEditorView = null
GlobalStylesElement = null
class TextEditorElement extends HTMLElement
model: null
componentDescriptor: null
@@ -18,13 +20,34 @@ class TextEditorElement extends HTMLElement
@initializeContent()
@createSpacePenShim()
@addEventListener 'focus', @focused.bind(this)
@addEventListener 'focusout', @focusedOut.bind(this)
@addEventListener 'blur', @blurred.bind(this)
initializeContent: (attributes) ->
@classList.add('editor', 'react', 'editor-colors')
@classList.add('editor')
@setAttribute('tabindex', -1)
if atom.config.get('editor.useShadowDOM')
@createShadowRoot()
@stylesElement = document.createElement('atom-styles')
@stylesElement.setAttribute('context', 'atom-text-editor')
@stylesElement.initialize()
@rootElement = document.createElement('div')
@rootElement.classList.add('editor', 'editor-colors')
@shadowRoot.appendChild(@stylesElement)
@shadowRoot.appendChild(@rootElement)
else
unless GlobalStylesElement?
GlobalStylesElement = document.createElement('atom-styles')
GlobalStylesElement.setAttribute('context', 'atom-text-editor')
GlobalStylesElement.initialize()
document.head.appendChild(GlobalStylesElement)
@stylesElement = GlobalStylesElement
@rootElement = this
createSpacePenShim: ->
TextEditorView ?= require './text-editor-view'
@__spacePenView = new TextEditorView(this)
@@ -64,12 +87,19 @@ class TextEditorElement extends HTMLElement
mountComponent: ->
@componentDescriptor ?= TextEditorComponent(
parentView: this
hostElement: this
rootElement: @rootElement
stylesElement: @stylesElement
editor: @model
mini: @model.mini
lineOverdrawMargin: @lineOverdrawMargin
)
@component = React.renderComponent(@componentDescriptor, this)
@component = React.renderComponent(@componentDescriptor, @rootElement)
unless atom.config.get('editor.useShadowDOM')
inputNode = @component.refs.input.getDOMNode()
inputNode.addEventListener 'focus', @focused.bind(this)
inputNode.addEventListener 'blur', => @dispatchEvent(new FocusEvent('blur', bubbles: false))
unmountComponent: ->
return unless @component?.isMounted()
@@ -79,15 +109,17 @@ class TextEditorElement extends HTMLElement
focused: ->
if @component?
@component.onFocus()
@component.focused()
else
@focusOnAttach = true
focusedOut: (event) ->
event.stopImmediatePropagation() if @contains(event.relatedTarget)
blurred: (event) ->
event.stopImmediatePropagation() if @contains(event.relatedTarget)
unless atom.config.get('editor.useShadowDOM')
if event.relatedTarget is @component?.refs.input?.getDOMNode()
event.stopImmediatePropagation()
return
@component?.blurred()
addGrammarScopeAttribute: ->
grammarScope = @model.getGrammar()?.scopeName?.replace(/\./g, ' ')

View File

@@ -73,13 +73,26 @@ class TextEditorView extends View
setModel: (@model) ->
@editor = @model
@scrollView = @find('.scroll-view')
@underlayer = @find('.highlights').addClass('underlayer')
@overlayer = @find('.lines').addClass('overlayer')
@hiddenInput = @.find('.hidden-input')
@root = $(@element.rootElement)
@scrollView = @root.find('.scroll-view')
if atom.config.get('editor.useShadowDOM')
@underlayer = $("<div class='underlayer'></div>").appendTo(this)
@overlayer = $("<div class='overlayer'></div>").appendTo(this)
else
@underlayer = @find('.highlights').addClass('underlayer')
@overlayer = @find('.lines').addClass('overlayer')
@hiddenInput = @root.find('.hidden-input')
@hiddenInput.on = (args...) =>
args[0] = 'blur' if args[0] is 'focusout'
$::on.apply(this, args)
@subscribe atom.config.observe 'editor.showLineNumbers', =>
@gutter = @find('.gutter')
@gutter = @root.find('.gutter')
@gutter.removeClassFromAllLines = (klass) =>
deprecate('Use decorations instead: http://blog.atom.io/2014/07/24/decorations.html')
@@ -95,6 +108,13 @@ class TextEditorView extends View
lines.addClass(klass)
lines.length > 0
find: ->
shadowResult = @root.find.apply(@root, arguments)
if shadowResult.length > 0
shadowResult
else
super
# Public: Get the underlying editor model for this view.
#
# Returns an {TextEditor}
@@ -107,7 +127,7 @@ class TextEditorView extends View
Object.defineProperty @::, 'firstRenderedScreenRow', get: -> @component.getRenderedRowRange()[0]
Object.defineProperty @::, 'lastRenderedScreenRow', get: -> @component.getRenderedRowRange()[1]
Object.defineProperty @::, 'active', get: -> @is(@getPaneView()?.activeView)
Object.defineProperty @::, 'isFocused', get: -> @component?.state.focused
Object.defineProperty @::, 'isFocused', get: -> document.activeElement is @element or document.activeElement is @element.component?.refs.input.getDOMNode()
Object.defineProperty @::, 'mini', get: -> @component?.props.mini
Object.defineProperty @::, 'component', get: -> @element?.component
@@ -164,7 +184,7 @@ class TextEditorView extends View
appendToLinesView: (view) ->
view.css('position', 'absolute')
view.css('z-index', 1)
@find('.lines').prepend(view)
@overlayer.append(view)
unmountComponent: ->
React.unmountComponentAtNode(@element) if @component.isMounted()

View File

@@ -249,6 +249,9 @@ class ThemeManager
if nativeStylesheetPath = fs.resolveOnLoadPath(process.platform, ['css', 'less'])
@requireStylesheet(nativeStylesheetPath)
textEditorStylesPath = path.join(@resourcePath, 'static', 'text-editor-shadow.less')
atom.styles.addStyleSheet(@loadLessStylesheet(textEditorStylesPath), sourcePath: textEditorStylesPath, context: 'atom-text-editor')
stylesheetElementForId: (id) ->
document.head.querySelector("atom-styles style[source-path=\"#{id}\"]")