UNPKG

react-native-dots-pagination

Version:

Paging as dots for react-native.

202 lines (171 loc) 4.91 kB
import React, { Component } from 'react'; import { View, ScrollView, Platform } from 'react-native'; import PropTypes from 'prop-types'; // Styles import { Styles } from './styles'; // set to fit const scalesPageToFit = Platform.OS === 'android'; const DEFAULT_PASSIVE_DOT_WIDTH = 10; const DEFAULT_ACTIVE_DOT_WIDTH = 10; export default class Dots extends Component { static get propTypes() { return { length: PropTypes.number.isRequired, active: PropTypes.number.isRequired, width: PropTypes.number, paddingVertical: PropTypes.number, paddingHorizontal: PropTypes.number, // Dots passiveDotWidth: PropTypes.number, activeDotWidth: PropTypes.number, activeDotHeight: PropTypes.number, passiveDotHeight: PropTypes.number, passiveColor: PropTypes.string, activeColor: PropTypes.string, // active Border activeBorder: PropTypes.bool, activeBorderColor: PropTypes.string, activeBorderWidth: PropTypes.number, // events onScrollTo: PropTypes.func, // accessibility accessible: PropTypes.bool, accessibilityLabel: PropTypes.string, }; } static defaultProps = { width: 300, marginHorizontal: 2, paddingVertical: 10, paddingHorizontal: 10, passiveDotWidth: DEFAULT_PASSIVE_DOT_WIDTH, activeDotWidth: DEFAULT_ACTIVE_DOT_WIDTH, activeDotHeight: DEFAULT_ACTIVE_DOT_WIDTH, passiveDotHeight: DEFAULT_PASSIVE_DOT_WIDTH, passiveColor: '#CCCCCC', activeColor: '#016bd8', activeBorder: false, activeBorderWidth: 3, activeBorderColor: '#FFF', // events onScrollTo() { // this function on change index. }, accessible: false, accessibilityLabel: '', }; componentDidUpdate(prevProps) { const newActive = this.props.active; if (prevProps.active !== newActive) { this.scrollTo(newActive); } } scrollTo(index) { const { width, activeDotWidth, onScrollTo } = this.props; const key = `dots_${index}`; const get = this[key]; if (get) { const x = get.x - (width / 2 - activeDotWidth); this.scrollRef.scrollTo({ x }); // on change event onScrollTo(index, key); } } isActive(index) { return this.props.active === index; } dotStyle(isActive) { const { activeDotWidth, passiveDotWidth, activeDotHeight, passiveDotHeight, activeColor, passiveColor, activeBorder, activeBorderWidth, activeBorderColor, marginHorizontal, alignDotsOnXAxis, } = this.props; const width = isActive ? activeDotWidth : passiveDotWidth; const marginTop = alignDotsOnXAxis || !isActive ? 0 : -width / 6; let height = width; if (isActive && activeDotHeight != null) { height = activeDotHeight; } else if (!isActive && passiveDotHeight != null) { height = passiveDotHeight; } let style = { width, height, marginHorizontal, backgroundColor: isActive ? activeColor : passiveColor, borderRadius: width, marginTop, }; // active Border Styles. if (activeBorder && isActive) { style.borderWidth = activeBorderWidth; style.borderColor = activeBorderColor; } return style; } render() { const { length, width, paddingVertical, paddingHorizontal, activeDotWidth, activeBorderWidth, passiveDotWidth, marginHorizontal, accessible, accessibilityLabel, } = this.props; const list = [...Array(length).keys()]; const activeWidth = activeBorderWidth * 4 + activeDotWidth + paddingHorizontal; const scrollWidth = activeWidth + (list.length - 1) * passiveDotWidth + marginHorizontal * (list.length * 2); return ( <View style={Styles.container} accessible={accessible} accessibilityLabel={accessibilityLabel}> <ScrollView ref={(el) => { this.scrollRef = el; }} style={{ width: width < scrollWidth ? width : scrollWidth }} contentContainerStyle={{ alignItems: 'center', paddingVertical, paddingHorizontal, }} scalesPageToFit={scalesPageToFit} bounces={false} horizontal={true} scrollEnabled={false} showsHorizontalScrollIndicator={false} > {list.map((i) => { return ( <View key={i} style={this.dotStyle(this.isActive(i))} onLayout={({ nativeEvent: { layout: { x, y }, }, }) => { this[`dots_${i}`] = { x, y }; }} /> ); })} </ScrollView> </View> ); } }