From 9fdaef6abc93e504df7bdec78ad50b7cf6460b70 Mon Sep 17 00:00:00 2001 From: Leonardo Andres Garcia Crespo Date: Tue, 4 Apr 2017 16:38:26 -0300 Subject: [PATCH] Add scrollToIndex support in WindowScroller --- .../WindowScroller/WindowScroller.example.js | 35 ++++++++++++++++--- source/WindowScroller/WindowScroller.js | 24 +++++++++++-- yarn.lock | 10 ++++++ 3 files changed, 62 insertions(+), 7 deletions(-) diff --git a/source/WindowScroller/WindowScroller.example.js b/source/WindowScroller/WindowScroller.example.js index 521847761..1ad6da3dc 100644 --- a/source/WindowScroller/WindowScroller.example.js +++ b/source/WindowScroller/WindowScroller.example.js @@ -3,6 +3,7 @@ import cn from 'classnames' import Immutable from 'immutable' import React, { PropTypes, PureComponent } from 'react' import { ContentBox, ContentBoxHeader, ContentBoxParagraph } from '../demo/ContentBox' +import { LabeledInput, InputRow } from '../demo/LabeledInput' import WindowScroller from './WindowScroller' import List from '../List' import AutoSizer from '../AutoSizer' @@ -20,18 +21,20 @@ export default class WindowScrollerExample extends PureComponent { super(props) this.state = { - showHeaderText: true + showHeaderText: true, + scrollToIndex: undefined } this._hideHeader = this._hideHeader.bind(this) this._rowRenderer = this._rowRenderer.bind(this) this._onCheckboxChange = this._onCheckboxChange.bind(this) + this._onScrollToRowChange = this._onScrollToRowChange.bind(this) this._setRef = this._setRef.bind(this) } render () { const { list, isScrollingCustomElement, customElement } = this.context - const { showHeaderText } = this.state + const { showHeaderText, scrollToIndex } = this.state return ( @@ -68,16 +71,25 @@ export default class WindowScrollerExample extends PureComponent { Use custom element for scrolling - + + +
- {({ height, isScrolling, scrollTop }) => ( + {({ height, isScrolling, scrollTop, onChildScroll }) => ( {({ width }) => ( { window.listEl = el }} autoHeight className={styles.List} height={height} @@ -86,7 +98,9 @@ export default class WindowScrollerExample extends PureComponent { rowHeight={30} rowRenderer={({ index, isVisible, key, style }) => this._rowRenderer({ index, isScrolling, isVisible, key, style })} scrollTop={scrollTop} + scrollToIndex={scrollToIndex} width={width} + onScroll={onChildScroll} /> )} @@ -121,7 +135,7 @@ export default class WindowScrollerExample extends PureComponent { className={className} style={style} > - {row.name} + {index}{row.name}
) } @@ -133,4 +147,15 @@ export default class WindowScrollerExample extends PureComponent { _onCheckboxChange (event) { this.context.setScrollingCustomElement(event.target.checked) } + + _onScrollToRowChange (event) { + const { list } = this.context + let scrollToIndex = Math.min(list.size - 1, parseInt(event.target.value, 10)) + + if (isNaN(scrollToIndex)) { + scrollToIndex = undefined + } + + this.setState({ scrollToIndex }) + } } diff --git a/source/WindowScroller/WindowScroller.js b/source/WindowScroller/WindowScroller.js index b771363a7..284e2b0bf 100644 --- a/source/WindowScroller/WindowScroller.js +++ b/source/WindowScroller/WindowScroller.js @@ -43,6 +43,7 @@ export default class WindowScroller extends PureComponent { } this._onResize = this._onResize.bind(this) + this._onChildScroll = this._onChildScroll.bind(this) this.__handleWindowScrollEvent = this.__handleWindowScrollEvent.bind(this) this.__resetIsScrolling = this.__resetIsScrolling.bind(this) } @@ -97,7 +98,6 @@ export default class WindowScroller extends PureComponent { componentWillUnmount () { unregisterScrollListener(this, this.props.scrollElement || window) - window.removeEventListener('resize', this._onResize, false) } @@ -108,7 +108,8 @@ export default class WindowScroller extends PureComponent { return children({ height, isScrolling, - scrollTop + scrollTop, + onChildScroll: this._onChildScroll }) } @@ -116,6 +117,25 @@ export default class WindowScroller extends PureComponent { this.updatePosition() } + _onChildScroll ({ scrollTop }) { + if (this.state.scrollTop === scrollTop) return + + // Need this setTimeout here because otherwise for some reason by the time the 'scroll' + // event that happens after the `scrollTo` call, the `window.scrollY` value is incorrect. + // Visually, if setTimeout is not here, the scroll position changes back to the top + // even after calling `scrollTo` below. + // What makes this even weirder, this happens only if you scroll to a row index + // via the `scrollToRow` prop. This does not happen with the imperative method. + setTimeout(() => { + const scrollElement = this.scrollElement + if (scrollElement.scrollTo) { + scrollElement.scrollTo(0, scrollTop + this._positionFromTop) + } else { + scrollElement.scrollTop = scrollTop + this._positionFromTop + } + }, 0) + } + // Referenced by utils/onScroll __handleWindowScrollEvent (event) { const { onScroll } = this.props diff --git a/yarn.lock b/yarn.lock index 566fb02e0..1bee4d8d2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1110,6 +1110,10 @@ binary-extensions@^1.0.0: version "1.7.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.7.0.tgz#6c1610db163abfb34edfe42fa423343a1e01185d" +binary-search-bounds@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/binary-search-bounds/-/binary-search-bounds-1.0.0.tgz#323ca317e3f2a40f4244c7255f5384a5b207bb69" + blessed@^0.1.81: version "0.1.81" resolved "https://registry.yarnpkg.com/blessed/-/blessed-0.1.81.tgz#f962d687ec2c369570ae71af843256e6d0ca1129" @@ -2840,6 +2844,12 @@ interpret@^0.6.4: version "0.6.6" resolved "https://registry.yarnpkg.com/interpret/-/interpret-0.6.6.tgz#fecd7a18e7ce5ca6abfb953e1f86213a49f1625b" +interval-tree-1d@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/interval-tree-1d/-/interval-tree-1d-1.0.3.tgz#8fdbde02b6b2c7dbdead636bcbed8e08710d85c1" + dependencies: + binary-search-bounds "^1.0.0" + invariant@^2.2.0, invariant@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.1.tgz#b097010547668c7e337028ebe816ebe36c8a8d54"