From bf28e7e680f599af6037b6c6cdc384f6b06f75b9 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Sat, 22 Dec 2018 11:43:05 -0800 Subject: [PATCH] Scroll to skin if needed --- src/SkinTable.js | 56 ++++++++++++++++++++++++++++++++++++------ src/redux/selectors.js | 5 +++- 2 files changed, 52 insertions(+), 9 deletions(-) diff --git a/src/SkinTable.js b/src/SkinTable.js index 8c98748e..aa69c799 100644 --- a/src/SkinTable.js +++ b/src/SkinTable.js @@ -52,6 +52,7 @@ class SkinTable extends React.Component { // Our initial render may have caused the scrollbar to appear. So we // remeasure. this._handleResize(); + this._scrollToSelectedSkinIfNeeded(); } componentWillUnmount() { @@ -59,6 +60,32 @@ class SkinTable extends React.Component { window.removeEventListener("resize", this._handleResize); } + componentDidUpdate() { + this._scrollToSelectedSkinIfNeeded(); + } + + _scrollToSelectedSkinIfNeeded() { + if (this.props.selectedSkinHash == null) { + return; + } + + const selectedHashIndex = this.props.skinHashes.indexOf( + this.props.selectedSkinHash + ); + + const { start, end } = this._rangeToRender(); + if (selectedHashIndex < start || selectedHashIndex > end) { + const { columnCount, rowHeight } = this._getTableDimensions(); + const row = Math.floor(selectedHashIndex / columnCount); + const scrollTop = + row * rowHeight - (this.state.windowHeight - rowHeight) / 2; + window.scrollTo({ + left: 0, + top: scrollTop + }); + } + } + _handleScroll() { // If there's a timer, cancel it if (this._timeout) { @@ -82,14 +109,27 @@ class SkinTable extends React.Component { return { columnWidth, rowHeight, columnCount }; } - render() { - const { columnWidth, rowHeight, columnCount } = this._getTableDimensions(); + _rangeToRender() { + const { rowHeight, columnCount } = this._getTableDimensions(); const hashes = this.props.skinHashes; // Add one since we might be showing half a row at the top, and half a row at the bottom const visibleRows = Math.ceil(this.state.windowHeight / rowHeight) + 1; const topRow = Math.floor(this.state.scrollTop / rowHeight); + const firstHashToRender = topRow * columnCount; + const lastHashToRender = Math.min( + firstHashToRender + visibleRows * columnCount, + hashes.length + ); + + return { start: firstHashToRender, end: lastHashToRender }; + } + + render() { + const { columnWidth, rowHeight, columnCount } = this._getTableDimensions(); + const hashes = this.props.skinHashes; + const overscanRowsDown = this.state.scrollDirection === "DOWN" ? OVERSCAN_ROWS_LEADING @@ -99,11 +139,10 @@ class SkinTable extends React.Component { ? OVERSCAN_ROWS_LEADING : OVERSCAN_ROWS_TRAILING; - const firstHashToRender = topRow * columnCount; - const lastHashToRender = Math.min( - firstHashToRender + visibleRows * columnCount, - hashes.length - ); + const { + start: firstHashToRender, + end: lastHashToRender + } = this._rangeToRender(); const firstOverscanHashToRender = Math.max( firstHashToRender - overscanRowsUp * columnCount, @@ -154,7 +193,8 @@ class SkinTable extends React.Component { const mapStateToProps = state => ({ skinHashes: Selectors.getMatchingSkinHashes(state), - skins: Selectors.getSkins(state) + skins: Selectors.getSkins(state), + selectedSkinHash: Selectors.getSelectedSkinHash(state) }); const mapDispatchToProps = dispatch => ({ diff --git a/src/redux/selectors.js b/src/redux/selectors.js index c622b427..c2e440d2 100644 --- a/src/redux/selectors.js +++ b/src/redux/selectors.js @@ -48,7 +48,10 @@ export const getMatchingSkinHashes = createSelector( // We should be careful _not_ to memoize this function since it's non determinisitc export function getRandomSkinHash(state) { - const skinHashes = getSkinHashes(state); + const matchingHashes = getMatchingHashes(state); + const skinHashes = matchingHashes + ? Array.from(matchingHashes) + : getSkinHashes(state); const numberOfSkins = skinHashes.length; const randomIndex = Math.floor(Math.random() * numberOfSkins); return skinHashes[randomIndex];