WIP: Start extracting gutter component

This commit is contained in:
Nathan Sobo
2017-04-24 04:45:13 -06:00
committed by Antonio Scandurra
parent 305fd14cd9
commit 1ca4c69c87
2 changed files with 115 additions and 94 deletions

View File

@@ -118,7 +118,7 @@ describe('TextEditorComponent', () => {
it('gives the line number tiles an explicit width and height so their layout can be strictly contained', async () => {
const {component, element, editor} = buildComponent({rowsPerTile: 3})
const lineNumberGutterElement = component.refs.lineNumberGutter.element
const lineNumberGutterElement = component.refs.gutterContainer.refs.lineNumberGutter.element
expect(lineNumberGutterElement.offsetHeight).toBe(component.getScrollHeight())
for (const child of lineNumberGutterElement.children) {
@@ -1421,7 +1421,7 @@ describe('TextEditorComponent', () => {
editor.addGutter({name: 'c', priority: 0})
await component.getNextUpdatePromise()
const gutters = component.refs.gutterContainer.querySelectorAll('.gutter')
const gutters = component.refs.gutterContainer.element.querySelectorAll('.gutter')
expect(Array.from(gutters).map((g) => g.getAttribute('gutter-name'))).toEqual([
'a', 'b', 'c', 'line-number', 'd', 'e'
])
@@ -1432,7 +1432,7 @@ describe('TextEditorComponent', () => {
const {scrollContainer, gutterContainer} = component.refs
function checkScrollContainerLeft () {
expect(scrollContainer.getBoundingClientRect().left).toBe(Math.round(gutterContainer.getBoundingClientRect().right))
expect(scrollContainer.getBoundingClientRect().left).toBe(Math.round(gutterContainer.element.getBoundingClientRect().right))
}
checkScrollContainerLeft()
@@ -3175,7 +3175,7 @@ function clientPositionForCharacter (component, row, column) {
}
function lineNumberNodeForScreenRow (component, row) {
const gutterElement = component.refs.lineNumberGutter.element
const gutterElement = component.refs.gutterContainer.refs.lineNumberGutter.element
const tileStartRow = component.tileStartRowForRow(row)
const tileIndex = component.tileIndexForTileStartRow(tileStartRow)
return gutterElement.children[tileIndex + 1].children[row - tileStartRow]

View File

@@ -123,7 +123,6 @@ class TextEditorComponent {
this.pendingScrollLeftColumn = this.props.initialScrollLeftColumn
this.measuredContent = false
this.gutterContainerVnode = null
this.cursorsVnode = null
this.placeholderTextVnode = null
@@ -311,7 +310,7 @@ class TextEditorComponent {
measureContentDuringUpdateSync () {
if (this.remeasureGutterDimensions) {
if (this.measureGutterDimensions()) {
this.gutterContainerVnode = null
// TODO: Ensure we update the gutter container in the second phase of the update
}
this.remeasureGutterDimensions = false
}
@@ -434,82 +433,13 @@ class TextEditorComponent {
}
renderGutterContainer () {
if (this.props.model.isMini()) return null
if (!this.measuredContent || !this.gutterContainerVnode) {
const innerStyle = {
willChange: 'transform',
display: 'flex'
}
let scrollHeight
if (this.measurements) {
innerStyle.transform = `translateY(${-this.getScrollTop()}px)`
scrollHeight = this.getScrollHeight()
}
this.gutterContainerVnode = $.div(
{
ref: 'gutterContainer',
key: 'gutterContainer',
className: 'gutter-container',
style: {
position: 'relative',
zIndex: 1,
backgroundColor: 'inherit'
}
},
$.div({style: innerStyle},
this.guttersToRender.map((gutter) => {
if (gutter.name === 'line-number') {
return this.renderLineNumberGutter(gutter)
} else {
return $(CustomGutterComponent, {
key: gutter,
element: gutter.getElement(),
name: gutter.name,
visible: gutter.isVisible(),
height: scrollHeight,
decorations: this.decorationsToRender.customGutter.get(gutter.name)
})
}
})
)
)
}
return this.gutterContainerVnode
}
renderLineNumberGutter (gutter) {
if (!this.props.model.isLineNumberGutterVisible()) return null
if (this.measurements) {
const {maxDigits, keys, bufferRows, softWrappedFlags, foldableFlags} = this.lineNumbersToRender
return $(LineNumberGutterComponent, {
ref: 'lineNumberGutter',
element: gutter.getElement(),
parentComponent: this,
startRow: this.getRenderedStartRow(),
endRow: this.getRenderedEndRow(),
rowsPerTile: this.getRowsPerTile(),
maxDigits: maxDigits,
keys: keys,
bufferRows: bufferRows,
softWrappedFlags: softWrappedFlags,
foldableFlags: foldableFlags,
decorations: this.decorationsToRender.lineNumbers,
blockDecorations: this.decorationsToRender.blocks,
didMeasureVisibleBlockDecoration: this.didMeasureVisibleBlockDecoration,
height: this.getScrollHeight(),
width: this.getLineNumberGutterWidth(),
lineHeight: this.getLineHeight()
})
if (this.props.model.isMini()) {
return null
} else {
return $(LineNumberGutterComponent, {
ref: 'lineNumberGutter',
element: gutter.getElement(),
maxDigits: this.lineNumbersToRender.maxDigits
return $(GutterContainer, {
ref: 'gutterContainer',
key: 'gutterContainer',
rootComponent: this
})
}
}
@@ -1253,7 +1183,7 @@ class TextEditorComponent {
if (this.refs.gutterContainer) {
this.gutterContainerResizeObserver = new ResizeObserver(this.didResizeGutterContainer.bind(this))
this.gutterContainerResizeObserver.observe(this.refs.gutterContainer)
this.gutterContainerResizeObserver.observe(this.refs.gutterContainer.element)
}
this.overlayComponents.forEach((component) => component.didAttach())
@@ -1404,7 +1334,7 @@ class TextEditorComponent {
if (this.measureGutterDimensions()) {
this.gutterContainerResizeObserver.disconnect()
this.scheduleUpdate()
process.nextTick(() => { this.gutterContainerResizeObserver.observe(this.refs.gutterContainer) })
process.nextTick(() => { this.gutterContainerResizeObserver.observe(this.refs.gutterContainer.element) })
}
}
@@ -1930,7 +1860,7 @@ class TextEditorComponent {
let dimensionsChanged = false
if (this.refs.gutterContainer) {
const gutterContainerWidth = this.refs.gutterContainer.offsetWidth
const gutterContainerWidth = this.refs.gutterContainer.element.offsetWidth
if (gutterContainerWidth !== this.measurements.gutterContainerWidth) {
dimensionsChanged = true
this.measurements.gutterContainerWidth = gutterContainerWidth
@@ -1939,8 +1869,8 @@ class TextEditorComponent {
this.measurements.gutterContainerWidth = 0
}
if (this.refs.lineNumberGutter) {
const lineNumberGutterWidth = this.refs.lineNumberGutter.element.offsetWidth
if (this.refs.gutterContainer && this.refs.gutterContainer.refs.lineNumberGutter) {
const lineNumberGutterWidth = this.refs.gutterContainer.refs.lineNumberGutter.element.offsetWidth
if (lineNumberGutterWidth !== this.measurements.lineNumberGutterWidth) {
dimensionsChanged = true
this.measurements.lineNumberGutterWidth = lineNumberGutterWidth
@@ -2679,6 +2609,97 @@ class DummyScrollbarComponent {
}
}
class GutterContainer {
constructor (props) {
this.props = props
etch.initialize(this)
}
update (props) {
this.props = props
etch.updateSync(this)
}
render () {
const {rootComponent} = this.props
const innerStyle = {
willChange: 'transform',
display: 'flex'
}
let scrollHeight
if (rootComponent.measurements) {
innerStyle.transform = `translateY(${-rootComponent.getScrollTop()}px)`
scrollHeight = rootComponent.getScrollHeight()
}
return $.div(
{
ref: 'gutterContainer',
key: 'gutterContainer',
className: 'gutter-container',
style: {
position: 'relative',
zIndex: 1,
backgroundColor: 'inherit'
}
},
$.div({style: innerStyle},
rootComponent.guttersToRender.map((gutter) => {
if (gutter.name === 'line-number') {
return this.renderLineNumberGutter(gutter)
} else {
return $(CustomGutterComponent, {
key: gutter,
element: gutter.getElement(),
name: gutter.name,
visible: gutter.isVisible(),
height: scrollHeight,
decorations: rootComponent.decorationsToRender.customGutter.get(gutter.name)
})
}
})
)
)
}
renderLineNumberGutter (gutter) {
const {rootComponent} = this.props
if (!rootComponent.props.model.isLineNumberGutterVisible()) return null
if (rootComponent.measurements) {
const {maxDigits, keys, bufferRows, softWrappedFlags, foldableFlags} = rootComponent.lineNumbersToRender
return $(LineNumberGutterComponent, {
ref: 'lineNumberGutter',
element: gutter.getElement(),
rootComponent: rootComponent,
startRow: rootComponent.getRenderedStartRow(),
endRow: rootComponent.getRenderedEndRow(),
rowsPerTile: rootComponent.getRowsPerTile(),
maxDigits: maxDigits,
keys: keys,
bufferRows: bufferRows,
softWrappedFlags: softWrappedFlags,
foldableFlags: foldableFlags,
decorations: rootComponent.decorationsToRender.lineNumbers,
blockDecorations: rootComponent.decorationsToRender.blocks,
didMeasureVisibleBlockDecoration: rootComponent.didMeasureVisibleBlockDecoration,
height: rootComponent.getScrollHeight(),
width: rootComponent.getLineNumberGutterWidth(),
lineHeight: rootComponent.getLineHeight()
})
} else {
return $(LineNumberGutterComponent, {
ref: 'lineNumberGutter',
element: gutter.getElement(),
maxDigits: rootComponent.lineNumbersToRender.maxDigits
})
}
}
}
class LineNumberGutterComponent {
constructor (props) {
this.props = props
@@ -2697,14 +2718,14 @@ class LineNumberGutterComponent {
render () {
const {
parentComponent, height, width, lineHeight, startRow, endRow, rowsPerTile,
rootComponent, height, width, lineHeight, startRow, endRow, rowsPerTile,
maxDigits, keys, bufferRows, softWrappedFlags, foldableFlags, decorations
} = this.props
let children = null
if (bufferRows) {
const renderedTileCount = parentComponent.getRenderedTileCount()
const renderedTileCount = rootComponent.getRenderedTileCount()
children = new Array(renderedTileCount)
for (let tileStartRow = startRow; tileStartRow < endRow; tileStartRow = tileStartRow + rowsPerTile) {
@@ -2733,8 +2754,8 @@ class LineNumberGutterComponent {
dataset: {bufferRow}
}
if (row === 0 || i > 0) {
let currentRowTop = parentComponent.pixelPositionAfterBlocksForRow(row)
let previousRowBottom = parentComponent.pixelPositionAfterBlocksForRow(row - 1) + lineHeight
let currentRowTop = rootComponent.pixelPositionAfterBlocksForRow(row)
let previousRowBottom = rootComponent.pixelPositionAfterBlocksForRow(row - 1) + lineHeight
if (currentRowTop > previousRowBottom) {
lineNumberProps.style.marginTop = (currentRowTop - previousRowBottom) + 'px'
}
@@ -2746,9 +2767,9 @@ class LineNumberGutterComponent {
)
}
const tileIndex = parentComponent.tileIndexForTileStartRow(tileStartRow)
const tileTop = parentComponent.pixelPositionBeforeBlocksForRow(tileStartRow)
const tileBottom = parentComponent.pixelPositionBeforeBlocksForRow(tileEndRow)
const tileIndex = rootComponent.tileIndexForTileStartRow(tileStartRow)
const tileTop = rootComponent.pixelPositionBeforeBlocksForRow(tileStartRow)
const tileBottom = rootComponent.pixelPositionBeforeBlocksForRow(tileEndRow)
const tileHeight = tileBottom - tileTop
children[tileIndex] = $.div({
@@ -2841,7 +2862,7 @@ class LineNumberGutterComponent {
}
didMouseDown (event) {
this.props.parentComponent.didMouseDownOnLineNumberGutter(event)
this.props.rootComponent.didMouseDownOnLineNumberGutter(event)
}
}