diff --git a/CHANGELOG.md b/CHANGELOG.md index 7272bf9f..e313f8c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,9 @@ ## NEXT VERSION - chore: stop relying on `onScrollbarPresenceChange` +- feat: replace `react-virtualized` with `react-window` +- feat: add scroll direction to `onScroll` +- feat: add `align` to `scrollToRow` # v1.1.1 (2019-04-27) diff --git a/package.json b/package.json index e230c349..74a2fc2a 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,8 @@ "memoize-one": "^5.0.0", "prop-types": "^15.6.0", "react-draggable": "^3.0.5", - "react-virtualized": "^9.18.5" + "react-virtualized-auto-sizer": "^1.0.2", + "react-window": "^1.8.1" }, "peerDependencies": { "react": "^16.0.0", diff --git a/src/AutoResizer.js b/src/AutoResizer.js index 7d3ba939..9a627b2d 100644 --- a/src/AutoResizer.js +++ b/src/AutoResizer.js @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import AutoSizer from 'react-virtualized/dist/commonjs/AutoSizer'; +import AutoSizer from 'react-virtualized-auto-sizer'; /** * Decorator component that automatically adjusts the width and height of a single child diff --git a/src/BaseTable.js b/src/BaseTable.js index fccc77c8..c5b068b2 100644 --- a/src/BaseTable.js +++ b/src/BaseTable.js @@ -176,15 +176,26 @@ class BaseTable extends React.PureComponent { } /** - * Ensure row is visible. - * This method can be used to safely scroll back to a row that a user has scrolled away from even if it was previously scrolled to. - * - * @param {number} rowIndex + * Scroll to the specified row. + * By default, the table will scroll as little as possible to ensure the row is visible. + * You can control the alignment of the row though by specifying an align property. Acceptable values are: + * + * - `auto` (default) - Scroll as little as possible to ensure the row is visible. + * (If the row is already visible, it won't scroll at all.) + * - `smart` - If the row is already visible, don't scroll at all. If it is less than one viewport away, + * scroll as little as possible so that it becomes visible. + * If it is more than one viewport away, scroll so that it is centered within the grid. + * - `center` - Center align the row within the table. + * - `end` - Align the row to the bottom, right hand side of the table. + * - `start` - Align the row to the top, left hand of the table. + + * @param {number} rowIndex + * @param {string} align */ - scrollToRow(rowIndex = 0) { - this.table && this.table.scrollToRow(rowIndex); - this.leftTable && this.leftTable.scrollToRow(rowIndex); - this.rightTable && this.rightTable.scrollToRow(rowIndex); + scrollToRow(rowIndex = 0, align = 'auto') { + this.table && this.table.scrollToRow(rowIndex, align); + this.leftTable && this.leftTable.scrollToRow(rowIndex, align); + this.rightTable && this.rightTable.scrollToRow(rowIndex, align); } /** @@ -1044,7 +1055,14 @@ BaseTable.propTypes = { overscanRowCount: PropTypes.number, /** * A callback function when scrolling the table - * The handler is of the shape of `({ scrollLeft, scrollTop }) => *` + * The handler is of the shape of `({ scrollLeft, scrollTop, horizontalScrollDirection, verticalScrollDirection, scrollUpdateWasRequested }) => *` + * + * `scrollLeft` and `scrollTop` are numbers. + * + * `horizontalDirection` and `verticalDirection` are either `forward` or `backward`. + * + * `scrollUpdateWasRequested` is a boolean. This value is true if the scroll was caused by `scrollTo*`, + * and false if it was the result of a user interaction in the browser. */ onScroll: PropTypes.func, /** diff --git a/src/GridTable.js b/src/GridTable.js index c3be429b..a618adda 100644 --- a/src/GridTable.js +++ b/src/GridTable.js @@ -1,10 +1,9 @@ import React from 'react'; import PropTypes from 'prop-types'; import cn from 'classnames'; -import Grid from 'react-virtualized/dist/commonjs/Grid'; +import { FixedSizeGrid as Grid } from 'react-window'; import Header from './TableHeader'; -import cellRangeRenderer from './cellRangeRenderer'; /** * A wrapper of the Grid for internal only @@ -15,10 +14,10 @@ class GridTable extends React.PureComponent { this._setHeaderRef = this._setHeaderRef.bind(this); this._setBodyRef = this._setBodyRef.bind(this); - this._handleSectionRendered = this._handleSectionRendered.bind(this); + this._itemKey = this._itemKey.bind(this); + this._handleItemsRendered = this._handleItemsRendered.bind(this); this.renderRow = this.renderRow.bind(this); - this.renderCellRange = this.renderCellRange.bind(this); } forceUpdateTable() { @@ -28,11 +27,11 @@ class GridTable extends React.PureComponent { scrollToPosition(args) { this.headerRef && this.headerRef.scrollTo(args.scrollLeft); - this.bodyRef && this.bodyRef.scrollToPosition(args); + this.bodyRef && this.bodyRef.scrollTo(args); } scrollToTop(scrollTop) { - this.bodyRef && this.bodyRef.scrollToPosition({ scrollTop }); + this.bodyRef && this.bodyRef.scrollTo({ scrollTop }); } scrollToLeft(scrollLeft) { @@ -40,12 +39,8 @@ class GridTable extends React.PureComponent { this.bodyRef && this.bodyRef.scrollToPosition({ scrollLeft }); } - scrollToRow(rowIndex = 0) { - this.bodyRef && - this.bodyRef.scrollToCell({ - rowIndex, - columnIndex: 0, - }); + scrollToRow(rowIndex = 0, align = 'auto') { + this.bodyRef && this.bodyRef.scrollToItem({ rowIndex, columnIndex: 0, align }); } renderRow(args) { @@ -54,12 +49,6 @@ class GridTable extends React.PureComponent { return rowRenderer({ ...args, columns, rowData }); } - renderCellRange(args) { - const { useIsScrolling } = this.props; - const isScrolling = useIsScrolling ? args.isScrolling : undefined; - return cellRangeRenderer({ ...args, useIsScrolling, isScrolling }); - } - render() { const { containerStyle, @@ -75,6 +64,7 @@ class GridTable extends React.PureComponent { useIsScrolling, onScroll, hoveredRowKey, + overscanRowCount, // omit from rest style, onScrollbarPresenceChange, @@ -92,19 +82,21 @@ class GridTable extends React.PureComponent { className={`${classPrefix}__body`} ref={this._setBodyRef} data={data} + itemKey={this._itemKey} frozenData={frozenData} width={width} height={Math.max(height - headerHeight - frozenRowsHeight, 0)} rowHeight={rowHeight} rowCount={data.length} + overscanRowsCount={overscanRowCount} columnWidth={bodyWidth} columnCount={1} - isScrollingOptOut={!useIsScrolling} - cellRenderer={this.renderRow} - cellRangeRenderer={this.renderCellRange} + overscanColumnsCount={0} + useIsScrolling={useIsScrolling} hoveredRowKey={hoveredRowKey} onScroll={onScroll} - onSectionRendered={this._handleSectionRendered} + onItemsRendered={this._handleItemsRendered} + children={this.renderRow} /> {headerHeight + frozenRowsHeight > 0 && ( // put header after body and reverse the display order via css @@ -137,6 +129,11 @@ class GridTable extends React.PureComponent { this.bodyRef = ref; } + _itemKey({ rowIndex }) { + const { data, rowKey } = this.props; + return data[rowIndex][rowKey]; + } + _getHeaderHeight() { const { headerHeight } = this.props; if (Array.isArray(headerHeight)) { @@ -145,14 +142,12 @@ class GridTable extends React.PureComponent { return headerHeight; } - _handleSectionRendered({ rowOverscanStartIndex, rowOverscanStopIndex, rowStartIndex, rowStopIndex }) { - const { onRowsRendered } = this.props; - - onRowsRendered({ - overscanStartIndex: rowOverscanStartIndex, - overscanStopIndex: rowOverscanStopIndex, - startIndex: rowStartIndex, - stopIndex: rowStopIndex, + _handleItemsRendered({ overscanRowStartIndex, overscanRowStopIndex, visibleRowStartIndex, visibleRowStopIndex }) { + this.props.onRowsRendered({ + overscanStartIndex: overscanRowStartIndex, + overscanStopIndex: overscanRowStopIndex, + startIndex: visibleRowStartIndex, + stopIndex: visibleRowStopIndex, }); } } @@ -169,8 +164,10 @@ GridTable.propTypes = { rowHeight: PropTypes.number.isRequired, columns: PropTypes.arrayOf(PropTypes.object).isRequired, data: PropTypes.arrayOf(PropTypes.object).isRequired, + rowKey: PropTypes.string.isRequired, frozenData: PropTypes.arrayOf(PropTypes.object), useIsScrolling: PropTypes.bool, + overscanRowCount: PropTypes.number, hoveredRowKey: PropTypes.string, style: PropTypes.object, onScrollbarPresenceChange: PropTypes.func, diff --git a/src/__snapshots__/BaseTable.spec.js.snap b/src/__snapshots__/BaseTable.spec.js.snap index 71449a05..bf15b1a7 100644 --- a/src/__snapshots__/BaseTable.spec.js.snap +++ b/src/__snapshots__/BaseTable.spec.js.snap @@ -16,37 +16,25 @@ exports[`Table renders correctly 1`] = ` role="table" >