react-native-surveys
Version:
Build your own forms, surveys and polls for your React Native apps.
326 lines (293 loc) • 8.18 kB
JavaScript
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;