From 1e202b6bd5e2da6dde6834c808dd47f82691c7ce Mon Sep 17 00:00:00 2001 From: krister Date: Sat, 22 Dec 2018 14:12:31 -0300 Subject: [PATCH] [add] ScrollView support for pagingEnabled Available in browsers that support CSS snappoints. Fix #1057 Close #1212 Co-authored-by: Nicolas Gallagher --- README.md | 2 +- .../__snapshots__/index-test.js.snap | 7 ++++ .../ScrollView/__tests__/index-test.js | 16 ++++++- .../src/exports/ScrollView/index.js | 42 +++++++++++++++---- .../src/exports/View/ViewStylePropTypes.js | 2 + .../ScrollView/ScrollViewScreen.js | 6 +++ 6 files changed, 66 insertions(+), 9 deletions(-) create mode 100644 packages/react-native-web/src/exports/ScrollView/__tests__/__snapshots__/index-test.js.snap diff --git a/README.md b/README.md index 440a9dbe..1bb83219 100644 --- a/README.md +++ b/README.md @@ -140,7 +140,7 @@ React Native v0.55 | Picker | ✓ | | | RefreshControl | ✘ | Not started ([#1027](https://github.com/necolas/react-native-web/issues/1027)). | | 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 | ✓ | | | Slider | ✘ | Not started ([#1022](https://github.com/necolas/react-native-web/issues/1022)). | | StatusBar | (✓) | Mock. No equivalent web APIs. | diff --git a/packages/react-native-web/src/exports/ScrollView/__tests__/__snapshots__/index-test.js.snap b/packages/react-native-web/src/exports/ScrollView/__tests__/__snapshots__/index-test.js.snap new file mode 100644 index 00000000..61e5bbe8 --- /dev/null +++ b/packages/react-native-web/src/exports/ScrollView/__tests__/__snapshots__/index-test.js.snap @@ -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"`; diff --git a/packages/react-native-web/src/exports/ScrollView/__tests__/index-test.js b/packages/react-native-web/src/exports/ScrollView/__tests__/index-test.js index 72d506c0..76c388c2 100644 --- a/packages/react-native-web/src/exports/ScrollView/__tests__/index-test.js +++ b/packages/react-native-web/src/exports/ScrollView/__tests__/index-test.js @@ -2,7 +2,8 @@ import React from 'react'; import ScrollView from '..'; -import { mount } from 'enzyme'; +import StyleSheet from '../../StyleSheet'; +import { mount, shallow } from 'enzyme'; describe('components/ScrollView', () => { test('instance method setNativeProps', () => { @@ -11,4 +12,17 @@ describe('components/ScrollView', () => { instance.setNativeProps(); }).not.toThrow(); }); + + test('"pagingEnabled" prop', () => { + const getStyleProp = (component, prop) => StyleSheet.flatten(component.prop('style'))[prop]; + + // false + const component = shallow(); + expect(getStyleProp(component, 'scrollSnapType')).toMatchSnapshot(); + + // true + component.setProps({ pagingEnabled: true }); + expect(getStyleProp(component, 'scrollSnapType')).toMatchSnapshot(); + expect(getStyleProp(component.children().childAt(0), 'scrollSnapAlign')).toMatchSnapshot(); + }); }); diff --git a/packages/react-native-web/src/exports/ScrollView/index.js b/packages/react-native-web/src/exports/ScrollView/index.js index 4574b2dd..7fa8bea5 100644 --- a/packages/react-native-web/src/exports/ScrollView/index.js +++ b/packages/react-native-web/src/exports/ScrollView/index.js @@ -137,10 +137,10 @@ const ScrollView = createReactClass({ onContentSizeChange, refreshControl, stickyHeaderIndices, + pagingEnabled, /* eslint-disable */ keyboardDismissMode, onScroll, - pagingEnabled, /* eslint-enable */ ...other } = this.props; @@ -164,11 +164,24 @@ const ScrollView = createReactClass({ }; } + const hasStickyHeaderIndices = !horizontal && Array.isArray(stickyHeaderIndices); const children = - !horizontal && Array.isArray(stickyHeaderIndices) + hasStickyHeaderIndices || pagingEnabled ? React.Children.map(this.props.children, (child, i) => { - if (child && stickyHeaderIndices.indexOf(i) > -1) { - return {child}; + if (child != null) { + const isSticky = hasStickyHeaderIndices && stickyHeaderIndices.indexOf(i) > -1; + if (isSticky || pagingEnabled) { + return ( + + {child} + + ); + } } else { return child; } @@ -181,15 +194,21 @@ const ScrollView = createReactClass({ children={children} collapsable={false} ref={this._setInnerViewRef} - style={[horizontal && styles.contentContainerHorizontal, contentContainerStyle]} + style={StyleSheet.compose( + horizontal && styles.contentContainerHorizontal, + contentContainerStyle + )} /> ); const baseStyle = horizontal ? styles.baseHorizontal : styles.baseVertical; + const pagingEnabledStyle = horizontal + ? styles.pagingEnabledHorizontal + : styles.pagingEnabledVertical; const props = { ...other, - style: [baseStyle, this.props.style], + style: [baseStyle, pagingEnabled && pagingEnabledStyle, this.props.style], onTouchStart: this.scrollResponderHandleTouchStart, onTouchMove: this.scrollResponderHandleTouchMove, onTouchEnd: this.scrollResponderHandleTouchEnd, @@ -223,7 +242,7 @@ const ScrollView = createReactClass({ } return ( - + {contentContainer} ); @@ -294,6 +313,15 @@ const styles = StyleSheet.create({ position: 'sticky', top: 0, zIndex: 10 + }, + pagingEnabledHorizontal: { + scrollSnapType: 'x mandatory' + }, + pagingEnabledVertical: { + scrollSnapType: 'y mandatory' + }, + pagingEnabledChild: { + scrollSnapAlign: 'start' } }); diff --git a/packages/react-native-web/src/exports/View/ViewStylePropTypes.js b/packages/react-native-web/src/exports/View/ViewStylePropTypes.js index 308ebaae..bf07b1de 100644 --- a/packages/react-native-web/src/exports/View/ViewStylePropTypes.js +++ b/packages/react-native-web/src/exports/View/ViewStylePropTypes.js @@ -51,6 +51,8 @@ const ViewStylePropTypes = { overscrollBehavior: overscrollBehaviorType, overscrollBehaviorX: overscrollBehaviorType, overscrollBehaviorY: overscrollBehaviorType, + scrollSnapAlign: string, + scrollSnapType: string, WebkitMaskImage: string, WebkitOverflowScrolling: oneOf(['auto', 'touch']) }; diff --git a/packages/website/storybook/1-components/ScrollView/ScrollViewScreen.js b/packages/website/storybook/1-components/ScrollView/ScrollViewScreen.js index dbf2a923..92e2893e 100644 --- a/packages/website/storybook/1-components/ScrollView/ScrollViewScreen.js +++ b/packages/website/storybook/1-components/ScrollView/ScrollViewScreen.js @@ -101,6 +101,12 @@ const ScrollViewScreen = () => ( ]} /> + +