diff --git a/source/Grid/Grid.jest.js b/source/Grid/Grid.jest.js index aa90370c1..7cabecfdd 100644 --- a/source/Grid/Grid.jest.js +++ b/source/Grid/Grid.jest.js @@ -366,6 +366,35 @@ describe('Grid', () => { expect(grid.state.scrollTop).toEqual(900) }) + it('should support scrollToPosition() public method', () => { + const grid = render(getMarkup()) + expect(grid.state.scrollLeft).toEqual(0) + expect(grid.state.scrollTop).toEqual(0) + + grid.scrollToPosition({ + scrollLeft: 50, + scrollTop: 50 + }) + expect(grid.state.scrollLeft).toEqual(50) + expect(grid.state.scrollTop).toEqual(50) + }) + + it('should support getOffsetForCell() public method', () => { + const grid = render(getMarkup()) + const { scrollLeft, scrollTop } = grid.getOffsetForCell({ + columnIndex: 24, + rowIndex: 49 + }) + // 100 columns * 50 item width = 5,000 total item width + // 4 columns can be visible at a time and :scrollLeft is initially 0, + // So the minimum amount of scrolling leaves the 25th item at the right (just scrolled into view). + expect(scrollLeft).toEqual(1050) + // 100 rows * 20 item height = 2,000 total item height + // 5 rows can be visible at a time and :scrollTop is initially 0, + // So the minimum amount of scrolling leaves the 50th item at the bottom (just scrolled into view). + expect(scrollTop).toEqual(900) + }) + // See issue #565 it('should update scroll position to account for changed cell sizes within a function prop wrapper', () => { let rowHeight = 20 diff --git a/source/Grid/Grid.js b/source/Grid/Grid.js index ec684d9c4..004067218 100644 --- a/source/Grid/Grid.js +++ b/source/Grid/Grid.js @@ -264,8 +264,6 @@ export default class Grid extends PureComponent { this._invokeOnGridRenderedHelper = this._invokeOnGridRenderedHelper.bind(this) this._onScroll = this._onScroll.bind(this) this._setScrollingContainerRef = this._setScrollingContainerRef.bind(this) - this._updateScrollLeftForScrollToColumn = this._updateScrollLeftForScrollToColumn.bind(this) - this._updateScrollTopForScrollToRow = this._updateScrollTopForScrollToRow.bind(this) this._columnWidthGetter = this._wrapSizeGetter(props.columnWidth) this._rowHeightGetter = this._wrapSizeGetter(props.rowHeight) @@ -381,6 +379,40 @@ export default class Grid extends PureComponent { }) } + /** + * Ensure offset position is visible + * Useful for animating position changes + */ + scrollToPosition ({ + scrollLeft, + scrollTop + } = {}) { + this._setScrollPosition({ scrollLeft, scrollTop }) + } + + /** + * Gets offsets for a given cell and alignment + */ + getOffsetForCell ({ + columnIndex, + rowIndex, + scrollToAlignment = this.props.scrollToAlignment + } = {}) { + const scrollToColumn = columnIndex >= 0 ? columnIndex : this.props.scrollToColumn + const scrollToRow = rowIndex >= 0 ? rowIndex : this.props.scrollToRow + const offsetProps = { + ...this.props, + scrollToColumn, + scrollToRow, + scrollToAlignment + } + + return { + scrollLeft: this._getCalculatedScrollLeft(offsetProps), + scrollTop: this._getCalculatedScrollTop(offsetProps) + } + } + componentDidMount () { const { getScrollbarSize, scrollLeft, scrollToColumn, scrollTop, scrollToRow } = this.props @@ -999,7 +1031,7 @@ export default class Grid extends PureComponent { return this._wrapPropertyGetter(size) } - _updateScrollLeftForScrollToColumn (props = this.props, state = this.state) { + _getCalculatedScrollLeft (props = this.props, state = this.state) { const { columnCount, height, scrollToAlignment, scrollToColumn, width } = props const { scrollLeft } = state @@ -1008,22 +1040,27 @@ export default class Grid extends PureComponent { const totalRowsHeight = this._rowSizeAndPositionManager.getTotalSize() const scrollBarSize = totalRowsHeight > height ? this._scrollbarSize : 0 - const calculatedScrollLeft = this._columnSizeAndPositionManager.getUpdatedOffsetForIndex({ + return this._columnSizeAndPositionManager.getUpdatedOffsetForIndex({ align: scrollToAlignment, containerSize: width - scrollBarSize, currentOffset: scrollLeft, targetIndex }) + } + } - if (scrollLeft !== calculatedScrollLeft) { - this._setScrollPosition({ - scrollLeft: calculatedScrollLeft - }) - } + _updateScrollLeftForScrollToColumn (props = this.props, state = this.state) { + const { scrollLeft } = state + const calculatedScrollLeft = this._getCalculatedScrollLeft(props, state) + + if (calculatedScrollLeft >= 0 && scrollLeft !== calculatedScrollLeft) { + this._setScrollPosition({ + scrollLeft: calculatedScrollLeft + }) } } - _updateScrollTopForScrollToRow (props = this.props, state = this.state) { + _getCalculatedScrollTop (props = this.props, state = this.state) { const { height, rowCount, scrollToAlignment, scrollToRow, width } = props const { scrollTop } = state @@ -1032,18 +1069,23 @@ export default class Grid extends PureComponent { const totalColumnsWidth = this._columnSizeAndPositionManager.getTotalSize() const scrollBarSize = totalColumnsWidth > width ? this._scrollbarSize : 0 - const calculatedScrollTop = this._rowSizeAndPositionManager.getUpdatedOffsetForIndex({ + return this._rowSizeAndPositionManager.getUpdatedOffsetForIndex({ align: scrollToAlignment, containerSize: height - scrollBarSize, currentOffset: scrollTop, targetIndex }) + } + } - if (scrollTop !== calculatedScrollTop) { - this._setScrollPosition({ - scrollTop: calculatedScrollTop - }) - } + _updateScrollTopForScrollToRow (props = this.props, state = this.state) { + const { scrollTop } = state + const calculatedScrollTop = this._getCalculatedScrollTop(props, state) + + if (calculatedScrollTop >= 0 && scrollTop !== calculatedScrollTop) { + this._setScrollPosition({ + scrollTop: calculatedScrollTop + }) } } diff --git a/source/List/List.js b/source/List/List.js index 7a4f257cf..d70b56fa8 100644 --- a/source/List/List.js +++ b/source/List/List.js @@ -122,6 +122,19 @@ export default class List extends PureComponent { }) } + /** See Grid#getOffsetForCell */ + getOffsetForRow ({ + rowIndex, + scrollToAlignment + }) { + const { scrollTop } = this.Grid.getOffsetForCell({ + columnIndex: 0, + rowIndex, + scrollToAlignment + }) + return scrollTop + } + /** See Grid#scrollToCell */ scrollToRow (index = 0) { this.Grid.scrollToCell({ @@ -130,6 +143,11 @@ export default class List extends PureComponent { }) } + /** See Grid#scrollToPosition */ + scrollToPosition (scrollTop = 0) { + this.Grid.scrollToPosition({ scrollTop }) + } + render () { const { className,