[add] ScrollView support for pagingEnabled

Available in browsers that support CSS snappoints.

Fix #1057
Close #1212

Co-authored-by: Nicolas Gallagher <nicolasgallagher@gmail.com>
This commit is contained in:
krister
2018-12-22 14:12:31 -03:00
committed by Nicolas Gallagher
parent 2b77bfd853
commit 1e202b6bd5
6 changed files with 66 additions and 9 deletions
+1 -1
View File
@@ -140,7 +140,7 @@ React Native v0.55
| Picker | ✓ | | | Picker | ✓ | |
| RefreshControl | ✘ | Not started ([#1027](https://github.com/necolas/react-native-web/issues/1027)). | | RefreshControl | ✘ | Not started ([#1027](https://github.com/necolas/react-native-web/issues/1027)). |
| SafeAreaView | ✓ | | | SafeAreaView | ✓ | |
| ScrollView | ✓ | Missing momentum scroll events ([#1021](https://github.com/necolas/react-native-web/issues/1021)) and `pagingEnabled` ([#1057](https://github.com/necolas/react-native-web/issues/1057)). | | ScrollView | ✓ | Missing momentum scroll events ([#1021](https://github.com/necolas/react-native-web/issues/1021)). |
| SectionList | ✓ | | | SectionList | ✓ | |
| Slider | ✘ | Not started ([#1022](https://github.com/necolas/react-native-web/issues/1022)). | | Slider | ✘ | Not started ([#1022](https://github.com/necolas/react-native-web/issues/1022)). |
| StatusBar | (✓) | Mock. No equivalent web APIs. | | StatusBar | (✓) | Mock. No equivalent web APIs. |
@@ -0,0 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`components/ScrollView "pagingEnabled" prop 1`] = `undefined`;
exports[`components/ScrollView "pagingEnabled" prop 2`] = `"y mandatory"`;
exports[`components/ScrollView "pagingEnabled" prop 3`] = `"start"`;
@@ -2,7 +2,8 @@
import React from 'react'; import React from 'react';
import ScrollView from '..'; import ScrollView from '..';
import { mount } from 'enzyme'; import StyleSheet from '../../StyleSheet';
import { mount, shallow } from 'enzyme';
describe('components/ScrollView', () => { describe('components/ScrollView', () => {
test('instance method setNativeProps', () => { test('instance method setNativeProps', () => {
@@ -11,4 +12,17 @@ describe('components/ScrollView', () => {
instance.setNativeProps(); instance.setNativeProps();
}).not.toThrow(); }).not.toThrow();
}); });
test('"pagingEnabled" prop', () => {
const getStyleProp = (component, prop) => StyleSheet.flatten(component.prop('style'))[prop];
// false
const component = shallow(<ScrollView children={'Child'} />);
expect(getStyleProp(component, 'scrollSnapType')).toMatchSnapshot();
// true
component.setProps({ pagingEnabled: true });
expect(getStyleProp(component, 'scrollSnapType')).toMatchSnapshot();
expect(getStyleProp(component.children().childAt(0), 'scrollSnapAlign')).toMatchSnapshot();
});
}); });
+35 -7
View File
@@ -137,10 +137,10 @@ const ScrollView = createReactClass({
onContentSizeChange, onContentSizeChange,
refreshControl, refreshControl,
stickyHeaderIndices, stickyHeaderIndices,
pagingEnabled,
/* eslint-disable */ /* eslint-disable */
keyboardDismissMode, keyboardDismissMode,
onScroll, onScroll,
pagingEnabled,
/* eslint-enable */ /* eslint-enable */
...other ...other
} = this.props; } = this.props;
@@ -164,11 +164,24 @@ const ScrollView = createReactClass({
}; };
} }
const hasStickyHeaderIndices = !horizontal && Array.isArray(stickyHeaderIndices);
const children = const children =
!horizontal && Array.isArray(stickyHeaderIndices) hasStickyHeaderIndices || pagingEnabled
? React.Children.map(this.props.children, (child, i) => { ? React.Children.map(this.props.children, (child, i) => {
if (child && stickyHeaderIndices.indexOf(i) > -1) { if (child != null) {
return <View style={styles.stickyHeader}>{child}</View>; const isSticky = hasStickyHeaderIndices && stickyHeaderIndices.indexOf(i) > -1;
if (isSticky || pagingEnabled) {
return (
<View
style={StyleSheet.compose(
isSticky && styles.stickyHeader,
pagingEnabled && styles.pagingEnabledChild
)}
>
{child}
</View>
);
}
} else { } else {
return child; return child;
} }
@@ -181,15 +194,21 @@ const ScrollView = createReactClass({
children={children} children={children}
collapsable={false} collapsable={false}
ref={this._setInnerViewRef} ref={this._setInnerViewRef}
style={[horizontal && styles.contentContainerHorizontal, contentContainerStyle]} style={StyleSheet.compose(
horizontal && styles.contentContainerHorizontal,
contentContainerStyle
)}
/> />
); );
const baseStyle = horizontal ? styles.baseHorizontal : styles.baseVertical; const baseStyle = horizontal ? styles.baseHorizontal : styles.baseVertical;
const pagingEnabledStyle = horizontal
? styles.pagingEnabledHorizontal
: styles.pagingEnabledVertical;
const props = { const props = {
...other, ...other,
style: [baseStyle, this.props.style], style: [baseStyle, pagingEnabled && pagingEnabledStyle, this.props.style],
onTouchStart: this.scrollResponderHandleTouchStart, onTouchStart: this.scrollResponderHandleTouchStart,
onTouchMove: this.scrollResponderHandleTouchMove, onTouchMove: this.scrollResponderHandleTouchMove,
onTouchEnd: this.scrollResponderHandleTouchEnd, onTouchEnd: this.scrollResponderHandleTouchEnd,
@@ -223,7 +242,7 @@ const ScrollView = createReactClass({
} }
return ( return (
<ScrollViewClass {...props} ref={this._setScrollViewRef} style={props.style}> <ScrollViewClass {...props} ref={this._setScrollViewRef}>
{contentContainer} {contentContainer}
</ScrollViewClass> </ScrollViewClass>
); );
@@ -294,6 +313,15 @@ const styles = StyleSheet.create({
position: 'sticky', position: 'sticky',
top: 0, top: 0,
zIndex: 10 zIndex: 10
},
pagingEnabledHorizontal: {
scrollSnapType: 'x mandatory'
},
pagingEnabledVertical: {
scrollSnapType: 'y mandatory'
},
pagingEnabledChild: {
scrollSnapAlign: 'start'
} }
}); });
@@ -51,6 +51,8 @@ const ViewStylePropTypes = {
overscrollBehavior: overscrollBehaviorType, overscrollBehavior: overscrollBehaviorType,
overscrollBehaviorX: overscrollBehaviorType, overscrollBehaviorX: overscrollBehaviorType,
overscrollBehaviorY: overscrollBehaviorType, overscrollBehaviorY: overscrollBehaviorType,
scrollSnapAlign: string,
scrollSnapType: string,
WebkitMaskImage: string, WebkitMaskImage: string,
WebkitOverflowScrolling: oneOf(['auto', 'touch']) WebkitOverflowScrolling: oneOf(['auto', 'touch'])
}; };
@@ -101,6 +101,12 @@ const ScrollViewScreen = () => (
]} ]}
/> />
<DocItem
name="pagingEnabled"
typeInfo="?boolean = false"
description="When true, the scroll view snaps to individual items in the list when scrolling."
/>
<DocItem <DocItem
name="scrollEnabled" name="scrollEnabled"
typeInfo="?boolean = true" typeInfo="?boolean = true"