UNPKG

react-native-surveys

Version:

Build your own forms, surveys and polls for your React Native apps.

326 lines (293 loc) 8.18 kB
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); } import React, { Component } from "react"; import { View, Text, StyleSheet, PanResponder, Platform } from "react-native"; import * as TimeUtil from "./time.js"; import { shallowEqual } from "./pureRender.js"; import { colors } from "../../theme"; import { MONTHS_MAP } from "./dataSource"; const DATE_HEIGHT = 40; const DATE_LENGTH = 10; const MIDDLE_INDEX = Math.floor(DATE_LENGTH / 2); const MIDDLE_Y = -DATE_HEIGHT * MIDDLE_INDEX; const isFunction = val => Object.prototype.toString.apply(val) === "[object Function]"; class DatePickerItem extends Component { constructor(props) { super(props); this.touchY = 0; this.translateY = 0; this.currentIndex = MIDDLE_INDEX; this.moveDateCount = 0; this.state = { translateY: MIDDLE_Y, marginTop: (this.currentIndex - MIDDLE_INDEX) * DATE_HEIGHT }; this.renderDatepickerItem = this.renderDatepickerItem.bind(this); this.handleContentTouch = this.handleContentTouch.bind(this); this._panResponder = PanResponder.create({ // Ask to be the responder: onPanResponderTerminationRequest: () => false, onStartShouldSetPanResponder: (evt, gestureState) => true, onStartShouldSetPanResponderCapture: (evt, gestureState) => true, onMoveShouldSetPanResponder: (evt, gestureState) => true, onMoveShouldSetPanResponderCapture: (evt, gestureState) => true, onPanResponderGrant: (evt, gestureState) => { this.handleContentTouch(gestureState, "start"); }, onPanResponderMove: (evt, gestureState) => { this.handleContentTouch(gestureState, "move"); }, onPanResponderRelease: (evt, gestureState) => { this.handleContentTouch(gestureState, "end"); }, onPanResponderTerminate: (evt, gestureState) => { this.handleContentTouch(gestureState, "end"); } }); } componentWillMount() { this._iniDates(this.props.value); } componentWillReceiveProps(nextProps) { if (nextProps.value.getTime() === this.props.value.getTime()) { return; } this._iniDates(nextProps.value); this.currentIndex = MIDDLE_INDEX; this.setState({ translateY: MIDDLE_Y, marginTop: (this.currentIndex - MIDDLE_INDEX) * DATE_HEIGHT }); } shouldComponentUpdate(nextProps, nextState) { return ( nextProps.value.getTime() !== this.props.value.getTime() || !shallowEqual(nextState, this.state) ); } _iniDates(date) { const typeName = this.props.type; const dates = Array(...Array(DATE_LENGTH)).map((value, index) => TimeUtil[`next${typeName}`]( date, (index - MIDDLE_INDEX) * this.props.step ) ); this.setState({ dates }); } _updateDates(direction) { const typeName = this.props.type; const { dates } = this.state; if (direction === 1) { this.currentIndex++; this.setState({ dates: [ ...dates.slice(1), TimeUtil[`next${typeName}`](dates[dates.length - 1], this.props.step) ], marginTop: (this.currentIndex - MIDDLE_INDEX) * DATE_HEIGHT }); } else { this.currentIndex--; this.setState({ dates: [ TimeUtil[`next${typeName}`](dates[0], -this.props.step), ...dates.slice(0, dates.length - 1) ], marginTop: (this.currentIndex - MIDDLE_INDEX) * DATE_HEIGHT }); } } _checkIsUpdateDates(direction, translateY) { return direction === 1 ? this.currentIndex * DATE_HEIGHT + DATE_HEIGHT / 2 < -translateY : this.currentIndex * DATE_HEIGHT - DATE_HEIGHT / 2 > -translateY; } _moveToNext(direction) { const date = this.state.dates[MIDDLE_INDEX]; const { max, min } = this.props; if ( direction === -1 && date.getTime() < min.getTime() && this.moveDateCount ) { this._updateDates(1); } else if ( direction === 1 && date.getTime() > max.getTime() && this.moveDateCount ) { this._updateDates(-1); } this._moveTo(this.refs.scroll, this.currentIndex); } _moveTo(obj, currentIndex) { this.props.onSelect(this.state.dates[MIDDLE_INDEX]); this.setState({ translateY: -currentIndex * DATE_HEIGHT }); } handleStart(event) { this.touchY = event.dy; this.translateY = this.state.translateY; this.moveDateCount = 0; } handleMove(event) { const touchY = event.dy; const dir = touchY - this.touchY; const translateY = this.translateY + dir; const direction = dir > 0 ? -1 : 1; const date = this.state.dates[MIDDLE_INDEX]; const { max, min } = this.props; if (date.getTime() < min.getTime() || date.getTime() > max.getTime()) { return; } if (this._checkIsUpdateDates(direction, translateY)) { this.moveDateCount = direction > 0 ? this.moveDateCount + 1 : this.moveDateCount - 1; this._updateDates(direction); } this.setState({ translateY }); } handleEnd(event) { const touchY = event.dy; const dir = touchY - this.touchY; const direction = dir > 0 ? -1 : 1; this._moveToNext(direction); } handleContentTouch(event, type) { if (this.props.isPreview) return; if (type === "start") { this.handleStart(event); } else if (type === "move") { this.handleMove(event); } else if (type === "end") { this.handleEnd(event); } } renderDatepickerItem(date, index) { let formatDate; if (isFunction(this.props.format)) { formatDate = this.props.format(date); } else { formatDate = TimeUtil.convertDate(date, this.props.format); } if (this.props.format === "M") { formatDate = MONTHS_MAP[formatDate]; } const textStyle = { color: this.props.textColor }; const cursor = Platform.OS === "web" ? { cursor: "pointer" } : {}; return React.createElement( Text, { style: [textStyle, styles.text, cursor], key: index }, formatDate ); } render() { const wheelStyle = { borderTopColor: this.props.isPreview ? colors.buttonBorder : this.props.color, borderBottomColor: this.props.isPreview ? colors.buttonBorder : this.props.color }; const select = Platform.OS === "web" ? { userSelect: "none" } : {}; return React.createElement( View, { style: styles.column }, React.createElement( View, _extends({}, this._panResponder.panHandlers, { style: styles.viewport }), React.createElement( View, { style: [wheelStyle, styles.wheel, select] }, React.createElement( View, { style: { transform: [ { translateY: this.state.translateY } ], marginTop: this.state.marginTop } }, this.state.dates.map(this.renderDatepickerItem) ) ) ) ); } } const styles = StyleSheet.create({ text: { height: 40, lineHeight: 40, fontSize: 19, display: "flex", flexDirection: "column", textAlign: "center" }, wheel: { position: "absolute", height: 40, top: "50%", marginTop: -20, width: "100%", borderTopWidth: 1, borderBottomWidth: 1, borderStyle: "solid" }, column: { flex: 1, marginHorizontal: 4 }, viewport: { height: 200, position: "relative", overflow: "hidden" } }); export default DatePickerItem;