UNPKG

react-native-ui-lib

Version:

[![Build Status](https://travis-ci.org/wix/react-native-ui-lib.svg?branch=master)](https://travis-ci.org/wix/react-native-ui-lib) [![npm](https://img.shields.io/npm/v/react-native-ui-lib.svg)](https://www.npmjs.com/package/react-native-ui-lib) [![NPM Down

166 lines (143 loc) 4.12 kB
import React from 'react'; import PropTypes from 'prop-types'; import {ScrollView, StyleSheet} from 'react-native'; import _ from 'lodash'; import {BaseComponent} from '../../commons'; import View from '../view'; import {Constants} from '../../helpers'; import * as presenter from './CarouselPresenter'; const OFFSET_PIXEL_CORRECTION = 5; /** * @description: Carousel for scrolling pages horizontally * @gif: https://media.giphy.com/media/l0HU7f8gjpRlMRhKw/giphy.gif, https://media.giphy.com/media/3oFzmcjX9OhpyckhcQ/giphy.gif * @example: https://github.com/wix/react-native-ui-lib/blob/master/demo/src/screens/componentScreens/CarouselScreen.js */ export default class Carousel extends BaseComponent { static displayName = 'Carousel'; static propTypes = { /** * this first page to start with */ initialPage: PropTypes.number, /** * the page width (all pages should have the same page) */ pageWidth: PropTypes.number, /** * if true, will have infinite scroll */ loop: PropTypes.bool, /** * callback for when page has changed */ onChangePage: PropTypes.func, /** * callback for onScroll event of the internall ScrollView */ onScroll: PropTypes.func, /** * the carousel style */ containerStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.number, PropTypes.array]), }; static defaultProps = { initialPage: 0, pageWidth: Constants.screenWidth, }; constructor(props) { super(props); this.state = { currentPage: props.initialPage, currentStandingPage: props.initialPage, }; this.onScroll = this.onScroll.bind(this); this.updateOffset = this.updateOffset.bind(this); } generateStyles() { this.styles = createStyles(this.props); } get pageWidth() { return Math.floor(this.props.pageWidth); } onScroll(event) { const {loop} = this.props; const offsetX = event.nativeEvent.contentOffset.x; if (offsetX >= 0) { const {currentStandingPage} = this.state; const newPage = presenter.calcPageIndex(offsetX, this.props); this.setState({currentPage: newPage}); // finished full page scroll if (offsetX % this.pageWidth <= OFFSET_PIXEL_CORRECTION) { this.setState({currentStandingPage: newPage}); if (currentStandingPage !== newPage) { _.invoke(this.props, 'onChangePage', newPage, currentStandingPage); } } } if (loop && presenter.isOutOfBounds(offsetX, this.props)) { this.updateOffset(); } _.invoke(this.props, 'onScroll', event); } updateOffset(animated = false) { const x = presenter.calcOffset(this.props, this.state); this.carousel.scrollTo({x, animated}); } componentDidMount() { setTimeout(() => { this.updateOffset(); }, 0); } cloneChild(child) { if (!child.key) { return child; } return React.cloneElement(child, { key: `${child.key}-clone`, }); } renderChildren() { const {children, loop} = this.props; const length = presenter.getChildrenLength(this.props); const childrenArray = React.Children.toArray(children); if (loop) { childrenArray.unshift(this.cloneChild(children[length - 1])); childrenArray.push(this.cloneChild(children[0])); } return childrenArray; } render() { const {containerStyle} = this.props; return ( <View flex style={containerStyle}> <ScrollView ref={(scrollView) => { this.carousel = scrollView; }} horizontal showsHorizontalScrollIndicator={false} pagingEnabled onScroll={this.onScroll} scrollEventThrottle={200} > {this.renderChildren()} </ScrollView> </View> ); } goToPage(pageIndex, animated = true) { this.setState( { currentPage: pageIndex, }, () => this.updateOffset(animated), ); } } function createStyles() { return StyleSheet.create({ // container: { // flex: 1, // }, }); }