function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } /** * Copyright (c) Nicolas Gallagher. * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * */ import createReactClass from 'create-react-class'; import dismissKeyboard from '../../modules/dismissKeyboard'; import invariant from 'fbjs/lib/invariant'; import ScrollResponder from '../../modules/ScrollResponder'; import ScrollViewBase from './ScrollViewBase'; import StyleSheet from '../StyleSheet'; import View from '../View'; import React from 'react'; var emptyObject = {}; /* eslint-disable react/prefer-es6-class */ var ScrollView = createReactClass({ displayName: "ScrollView", mixins: [ScrollResponder.Mixin], getInitialState: function getInitialState() { return this.scrollResponderMixinGetInitialState(); }, flashScrollIndicators: function flashScrollIndicators() { this.scrollResponderFlashScrollIndicators(); }, setNativeProps: function setNativeProps(props) { if (this._scrollNodeRef) { this._scrollNodeRef.setNativeProps(props); } }, /** * Returns a reference to the underlying scroll responder, which supports * operations like `scrollTo`. All ScrollView-like components should * implement this method so that they can be composed while providing access * to the underlying scroll responder's methods. */ getScrollResponder: function getScrollResponder() { return this; }, getScrollableNode: function getScrollableNode() { return this._scrollNodeRef; }, getInnerViewNode: function getInnerViewNode() { return this._innerViewRef; }, /** * Scrolls to a given x, y offset, either immediately or with a smooth animation. * Syntax: * * scrollTo(options: {x: number = 0; y: number = 0; animated: boolean = true}) * * Note: The weird argument 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. */ scrollTo: function scrollTo(y, x, animated) { if (typeof y === 'number') { console.warn('`scrollTo(y, x, animated)` is deprecated. Use `scrollTo({x: 5, y: 5, animated: true})` instead.'); } else { var _ref = y || emptyObject; x = _ref.x; y = _ref.y; animated = _ref.animated; } this.getScrollResponder().scrollResponderScrollTo({ x: x || 0, y: y || 0, animated: animated !== false }); }, /** * 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 scrollToEnd(options) { // Default to true var animated = (options && options.animated) !== false; var horizontal = this.props.horizontal; var scrollResponder = this.getScrollResponder(); var scrollResponderNode = scrollResponder.scrollResponderGetScrollableNode(); var x = horizontal ? scrollResponderNode.scrollWidth : 0; var y = horizontal ? 0 : scrollResponderNode.scrollHeight; scrollResponder.scrollResponderScrollTo({ x: x, y: y, animated: animated }); }, render: function render() { var _this$props = this.props, contentContainerStyle = _this$props.contentContainerStyle, horizontal = _this$props.horizontal, onContentSizeChange = _this$props.onContentSizeChange, refreshControl = _this$props.refreshControl, stickyHeaderIndices = _this$props.stickyHeaderIndices, pagingEnabled = _this$props.pagingEnabled, keyboardDismissMode = _this$props.keyboardDismissMode, onScroll = _this$props.onScroll, other = _objectWithoutPropertiesLoose(_this$props, ["contentContainerStyle", "horizontal", "onContentSizeChange", "refreshControl", "stickyHeaderIndices", "pagingEnabled", "keyboardDismissMode", "onScroll"]); if (process.env.NODE_ENV !== 'production' && this.props.style) { var style = StyleSheet.flatten(this.props.style); var childLayoutProps = ['alignItems', 'justifyContent'].filter(function (prop) { return style && style[prop] !== undefined; }); invariant(childLayoutProps.length === 0, "ScrollView child layout (" + JSON.stringify(childLayoutProps) + ") " + 'must be applied through the contentContainerStyle prop.'); } var contentSizeChangeProps = {}; if (onContentSizeChange) { contentSizeChangeProps = { onLayout: this._handleContentOnLayout }; } var hasStickyHeaderIndices = !horizontal && Array.isArray(stickyHeaderIndices); var children = hasStickyHeaderIndices || pagingEnabled ? React.Children.map(this.props.children, function (child, i) { var isSticky = hasStickyHeaderIndices && stickyHeaderIndices.indexOf(i) > -1; if (child != null && (isSticky || pagingEnabled)) { return React.createElement(View, { style: StyleSheet.compose(isSticky && styles.stickyHeader, pagingEnabled && styles.pagingEnabledChild) }, child); } else { return child; } }) : this.props.children; var contentContainer = React.createElement(View, _extends({}, contentSizeChangeProps, { children: children, collapsable: false, ref: this._setInnerViewRef, style: StyleSheet.compose(horizontal && styles.contentContainerHorizontal, contentContainerStyle) })); var baseStyle = horizontal ? styles.baseHorizontal : styles.baseVertical; var pagingEnabledStyle = horizontal ? styles.pagingEnabledHorizontal : styles.pagingEnabledVertical; var props = _objectSpread({}, other, { style: [baseStyle, pagingEnabled && pagingEnabledStyle, this.props.style], onTouchStart: this.scrollResponderHandleTouchStart, onTouchMove: this.scrollResponderHandleTouchMove, onTouchEnd: this.scrollResponderHandleTouchEnd, onScrollBeginDrag: this.scrollResponderHandleScrollBeginDrag, onScrollEndDrag: this.scrollResponderHandleScrollEndDrag, onMomentumScrollBegin: this.scrollResponderHandleMomentumScrollBegin, onMomentumScrollEnd: this.scrollResponderHandleMomentumScrollEnd, onStartShouldSetResponder: this.scrollResponderHandleStartShouldSetResponder, onStartShouldSetResponderCapture: this.scrollResponderHandleStartShouldSetResponderCapture, onScrollShouldSetResponder: this.scrollResponderHandleScrollShouldSetResponder, onScroll: this._handleScroll, onResponderGrant: this.scrollResponderHandleResponderGrant, onResponderTerminationRequest: this.scrollResponderHandleTerminationRequest, onResponderTerminate: this.scrollResponderHandleTerminate, onResponderRelease: this.scrollResponderHandleResponderRelease, onResponderReject: this.scrollResponderHandleResponderReject }); var ScrollViewClass = ScrollViewBase; invariant(ScrollViewClass !== undefined, 'ScrollViewClass must not be undefined'); if (refreshControl) { return React.cloneElement(refreshControl, { style: props.style }, React.createElement(ScrollViewClass, _extends({}, props, { ref: this._setScrollNodeRef, style: baseStyle }), contentContainer)); } return React.createElement(ScrollViewClass, _extends({}, props, { ref: this._setScrollNodeRef }), contentContainer); }, _handleContentOnLayout: function _handleContentOnLayout(e) { var _e$nativeEvent$layout = e.nativeEvent.layout, width = _e$nativeEvent$layout.width, height = _e$nativeEvent$layout.height; this.props.onContentSizeChange(width, height); }, _handleScroll: function _handleScroll(e) { if (process.env.NODE_ENV !== 'production') { if (this.props.onScroll && this.props.scrollEventThrottle == null) { console.log('You specified `onScroll` on a but not ' + '`scrollEventThrottle`. You will only receive one event. ' + 'Using `16` you get all the events but be aware that it may ' + "cause frame drops, use a bigger number if you don't need as " + 'much precision.'); } } if (this.props.keyboardDismissMode === 'on-drag') { dismissKeyboard(); } this.scrollResponderHandleScroll(e); }, _setInnerViewRef: function _setInnerViewRef(component) { this._innerViewRef = component; }, _setScrollNodeRef: function _setScrollNodeRef(component) { this._scrollNodeRef = component; } }); var commonStyle = { flexGrow: 1, flexShrink: 1, // Enable hardware compositing in modern browsers. // Creates a new layer with its own backing surface that can significantly // improve scroll performance. transform: [{ translateZ: 0 }], // iOS native scrolling WebkitOverflowScrolling: 'touch' }; var styles = StyleSheet.create({ baseVertical: _objectSpread({}, commonStyle, { flexDirection: 'column', overflowX: 'hidden', overflowY: 'auto' }), baseHorizontal: _objectSpread({}, commonStyle, { flexDirection: 'row', overflowX: 'auto', overflowY: 'hidden' }), contentContainerHorizontal: { flexDirection: 'row' }, stickyHeader: { position: 'sticky', top: 0, zIndex: 10 }, pagingEnabledHorizontal: { scrollSnapType: 'x mandatory' }, pagingEnabledVertical: { scrollSnapType: 'y mandatory' }, pagingEnabledChild: { scrollSnapAlign: 'start' } }); export default ScrollView;