Skip to content

Commit

Permalink
fix(ScrollView): Update ScrollView JS to latest from upstream (#993)
Browse files Browse the repository at this point in the history
Fixes #986
  • Loading branch information
rozele committed Feb 10, 2017
1 parent 320c3c1 commit 2dfd8b2
Showing 1 changed file with 109 additions and 35 deletions.
144 changes: 109 additions & 35 deletions Libraries/Components/ScrollView/ScrollView.windows.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,21 @@ const requireNativeComponent = require('requireNativeComponent');
*
* Doesn't yet support other contained responders from blocking this scroll
* view from becoming the responder.
*
*
* `<ScrollView>` vs `<ListView>` - which one to use?
* ScrollView simply renders all its react child components at once. That
* makes it very easy to understand and use.
* On the other hand, this has a performance downside. Imagine you have a very
* long list of items you want to display, worth of couple of your ScrollView’s
* heights. Creating JS components and native views upfront for all its items,
* which may not even be shown, will contribute to slow rendering of your
* screen and increased memory usage.
*
* This is where ListView comes into play. ListView renders items lazily,
* just when they are about to appear. This laziness comes at cost of a more
* complicated API, which is worth it unless you are rendering a small fixed
* set of items.
*/
const ScrollView = React.createClass({
propTypes: {
Expand Down Expand Up @@ -177,12 +192,18 @@ const ScrollView = React.createClass({
'on-drag',
]),
/**
* When false, tapping outside of the focused text input when the keyboard
* is up dismisses the keyboard. When true, the keyboard will not dismiss
* automatically, and the scroll view will not catch taps, but children of
* the scroll view can catch taps. The default value is false.
* Determines when the keyboard should stay visible after a tap.
*
* - 'never' (the default), tapping outside of the focused text input when the keyboard
* is up dismisses the keyboard. When this happens, children won't receive the tap.
* - 'always', the keyboard will not dismiss automatically, and the scroll view will not
* catch taps, but children of the scroll view can catch taps.
* - 'handled', the keyboard will not dismiss automatically when the tap was handled by
* a children, (or captured by an ancestor).
* - false, deprecated, use 'never' instead
* - true, deprecated, use 'always' instead
*/
keyboardShouldPersistTaps: PropTypes.bool,
keyboardShouldPersistTaps: PropTypes.oneOf(['always', 'never', 'handled', false, true]),
/**
* The maximum allowed zoom scale. The default value is 1.0.
* @platform ios
Expand Down Expand Up @@ -305,7 +326,8 @@ const ScrollView = React.createClass({

/**
* A RefreshControl component, used to provide pull-to-refresh
* functionality for the ScrollView.
* functionality for the ScrollView. Only works for vertical ScrollViews
* (`horizontal` prop must be `false`).
*
* See [RefreshControl](docs/refreshcontrol.html).
*/
Expand All @@ -329,6 +351,24 @@ const ScrollView = React.createClass({
*/
scrollPerfTag: PropTypes.string,

/**
* Used to override default value of overScroll mode.
*
* Possible values:
*
* - `'auto'` - Default value, allow a user to over-scroll
* this view only if the content is large enough to meaningfully scroll.
* - `'always'` - Always allow a user to over-scroll this view.
* - `'never'` - Never allow a user to over-scroll this view.
*
* @platform android
*/
overScrollMode: PropTypes.oneOf([
'auto',
'always',
'never',
]),

/**
* Enables zoom on a scroll view for Windows.
* @platform windows
Expand Down Expand Up @@ -367,11 +407,11 @@ const ScrollView = React.createClass({
/**
* Scrolls to a given x, y offset, either immediately or with a smooth animation.
*
* Syntax:
* Example:
*
* `scrollTo(options: {x: number = 0; y: number = 0; animated: boolean = true})`
* `scrollTo({x: 0; y: 0; animated: true})`
*
* Note: The weird argument signature is due to the fact that, for historical reasons,
* Note: The weird function signature is due to the fact that, for historical reasons,
* the function also accepts separate arguments as as alternative to the options object.
* This is deprecated due to ambiguity (y before x), and SHOULD NOT BE USED.
*/
Expand All @@ -389,7 +429,25 @@ const ScrollView = React.createClass({
},

/**
* Deprecated, do not use.
* If this is a vertical ScrollView scrolls to the bottom.
* If this is a horizontal ScrollView scrolls to the right.
*
* Use `scrollToEnd({animated: true})` for smooth animated scrolling,
* `scrollToEnd({animated: false})` for immediate scrolling.
* If no options are passed, `animated` defaults to true.
*/
scrollToEnd: function(
options?: { animated?: boolean },
) {
// Default to true
const animated = (options && options.animated) !== false;
this.getScrollResponder().scrollResponderScrollToEnd({
animated: animated,
});
},

/**
* Deprecated, use `scrollTo` instead.
*/
scrollWithoutAnimationTo: function(y: number = 0, x: number = 0) {
console.warn('`scrollWithoutAnimationTo` is deprecated. Use `scrollTo` instead');
Expand Down Expand Up @@ -432,6 +490,33 @@ const ScrollView = React.createClass({
},

render: function() {
let ScrollViewClass;
let ScrollContentContainerViewClass;
if (Platform.OS === 'ios') {
ScrollViewClass = RCTScrollView;
ScrollContentContainerViewClass = RCTScrollContentView;
} else if (Platform.OS === 'android') {
if (this.props.horizontal) {
ScrollViewClass = AndroidHorizontalScrollView;
} else {
ScrollViewClass = AndroidScrollView;
}
ScrollContentContainerViewClass = View;
} else if (Platform.OS === 'windows') {
ScrollViewClass = RCTScrollView;
ScrollContentContainerViewClass = View;
}

invariant(
ScrollViewClass !== undefined,
'ScrollViewClass must not be undefined'
);

invariant(
ScrollContentContainerViewClass !== undefined,
'ScrollContentContainerViewClass must not be undefined'
);

const contentContainerStyle = [
this.props.horizontal && styles.contentContainerHorizontal,
this.props.contentContainerStyle,
Expand All @@ -456,14 +541,14 @@ const ScrollView = React.createClass({
}

const contentContainer =
<View
<ScrollContentContainerViewClass
{...contentSizeChangeProps}
ref={this._setInnerViewRef}
style={contentContainerStyle}
removeClippedSubviews={this.props.removeClippedSubviews}
collapsable={false}>
{this.props.children}
</View>;
</ScrollContentContainerViewClass>;

const alwaysBounceHorizontal =
this.props.alwaysBounceHorizontal !== undefined ?
Expand Down Expand Up @@ -508,23 +593,6 @@ const ScrollView = React.createClass({
props.decelerationRate = processDecelerationRate(decelerationRate);
}

let ScrollViewClass;
if (Platform.OS === 'ios') {
ScrollViewClass = RCTScrollView;
} else if (Platform.OS === 'android') {
if (this.props.horizontal) {
ScrollViewClass = AndroidHorizontalScrollView;
} else {
ScrollViewClass = AndroidScrollView;
}
} else if (Platform.OS === 'windows') {
ScrollViewClass = RCTScrollView;
}
invariant(
ScrollViewClass !== undefined,
'ScrollViewClass must not be undefined'
);

const refreshControl = this.props.refreshControl;
if (refreshControl) {
if (Platform.OS === 'ios') {
Expand All @@ -539,10 +607,13 @@ const ScrollView = React.createClass({
// On Android wrap the ScrollView with a AndroidSwipeRefreshLayout.
// Since the ScrollView is wrapped add the style props to the
// AndroidSwipeRefreshLayout and use flex: 1 for the ScrollView.
// Note: we should only apply props.style on the wrapper
// however, the ScrollView still needs the baseStyle to be scrollable

return React.cloneElement(
refreshControl,
{style: props.style},
<ScrollViewClass {...props} ref={this._setScrollViewRef}>
<ScrollViewClass {...props} style={baseStyle} ref={this._setScrollViewRef}>
{contentContainer}
</ScrollViewClass>
);
Expand All @@ -558,12 +629,14 @@ const ScrollView = React.createClass({

const styles = StyleSheet.create({
baseVertical: {
flex: 1,
flexGrow: 1,
flexShrink: 1,
flexDirection: 'column',
overflow: 'scroll',
},
baseHorizontal: {
flex: 1,
flexGrow: 1,
flexShrink: 1,
flexDirection: 'row',
overflow: 'scroll',
},
Expand All @@ -572,7 +645,7 @@ const styles = StyleSheet.create({
},
});

let nativeOnlyProps, AndroidScrollView, AndroidHorizontalScrollView, RCTScrollView;
let nativeOnlyProps, AndroidScrollView, AndroidHorizontalScrollView, RCTScrollView, RCTScrollContentView;
if (Platform.OS === 'android') {
nativeOnlyProps = {
nativeOnly: {
Expand All @@ -595,8 +668,9 @@ if (Platform.OS === 'android') {
}
};
RCTScrollView = requireNativeComponent('RCTScrollView', ScrollView, nativeOnlyProps);
RCTScrollContentView = requireNativeComponent('RCTScrollContentView', View);
} else if (Platform.OS === 'windows') {
RCTScrollView = requireNativeComponent('RCTScrollView', ScrollView);
RCTScrollView = requireNativeComponent('RCTScrollView', ScrollView);
}

module.exports = ScrollView;
module.exports = ScrollView;

0 comments on commit 2dfd8b2

Please sign in to comment.