From 1ca4c69c873dffaccc697f5b9f5500bf961a7dad Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 24 Apr 2017 04:45:13 -0600 Subject: [PATCH] WIP: Start extracting gutter component --- spec/text-editor-component-spec.js | 8 +- src/text-editor-component.js | 201 ++++++++++++++++------------- 2 files changed, 115 insertions(+), 94 deletions(-) diff --git a/spec/text-editor-component-spec.js b/spec/text-editor-component-spec.js index b0601f311..cd72109c2 100644 --- a/spec/text-editor-component-spec.js +++ b/spec/text-editor-component-spec.js @@ -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] diff --git a/src/text-editor-component.js b/src/text-editor-component.js index 6d3a6f131..2d0634401 100644 --- a/src/text-editor-component.js +++ b/src/text-editor-component.js @@ -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) } }