react-native-common-date-picker
Version:
An awesome and cross-platform React Native date picker and calendar component for iOS and Android
528 lines (465 loc) • 17.3 kB
JavaScript
import React, {Component} from 'react';
import {FlatList, View} from 'react-native';
import PropTypes from 'prop-types';
import * as Constants from "../contants";
import WeekBar from "./components/WeekBar";
import ToolBar from "../components/ToolBar";
import ListItem from "./components/ListItem";
import {calculateCalendarDefaultDates} from '../contants';
class CalendarList extends Component {
constructor(props) {
super(props);
const {
startDate,
endDate,
} = calculateCalendarDefaultDates(props.defaultDates);
this.state = {
dataSource: [],
startDate,
endDate,
};
}
componentDidMount() {
const {minDate, maxDate, firstDayOnWeeks} = this.props;
this.setState({
dataSource: Constants.getCalendarDates(Constants.validateDate(minDate), Constants.validateDate(maxDate), firstDayOnWeeks),
});
}
/**
* Select date call back with date parameter.
* @param date A date string representing the date selected such as '2020-5-11'.
* @param index The click index.
*/
_selectDate = (date, index) => {
this.props.onPressDate(Constants.toStandardStringWith(date), index);
const {startDate, endDate} = this.state;
if (startDate && endDate) {
this.setState({
startDate: date,
endDate: '',
});
return;
}
if (startDate) {
const isBigger = Constants.greaterThan(startDate, date);
this.setState({
startDate: isBigger ? date : startDate,
endDate: isBigger ? startDate : date,
});
} else {
this.setState({startDate: date});
}
};
_renderItem = ({item, index}) => {
const {
minDate,
maxDate,
headerTitleType,
listItemStyle,
selectedDateMarkColor,
selectedDateMarkRangeColor,
beyondDatesDisabled,
beyondDatesDisabledTextColor,
horizontal,
rightArrowClick,
leftArrowClick,
hideArrow,
arrowAlign,
arrowColor,
arrowSize,
} = this.props;
return <ListItem
{...this.props}
item={item}
startDate={this.state.startDate}
endDate={this.state.endDate}
minDate={Constants.validateDate(minDate)}
maxDate={Constants.validateDate(maxDate)}
selectDate={this._selectDate}
headerTitleType={headerTitleType}
listItemStyle={listItemStyle}
selectedDateMarkColor={selectedDateMarkColor}
selectedDateMarkRangeColor={selectedDateMarkRangeColor}
beyondDatesDisabled={beyondDatesDisabled}
beyondDatesDisabledTextColor={beyondDatesDisabledTextColor}
horizontal={horizontal}
leftArrowClick={() => {
if (leftArrowClick && typeof leftArrowClick === 'function') {
leftArrowClick(index);
return;
}
if (this.props.inverted) {
if (index !== this.state.dataSource.length - 1) {
this.flatList.scrollToIndex({index: index + 1});
}
} else {
if (index !== 0) {
this.flatList.scrollToIndex({index: index - 1});
}
}
}}
rightArrowClick={() => {
if (rightArrowClick && typeof rightArrowClick === 'function') {
rightArrowClick(index);
return;
}
if (this.props.inverted) {
if (index !== 0) {
this.flatList.scrollToIndex({index: index - 1});
}
} else {
if (index !== this.state.dataSource.length - 1) {
this.flatList.scrollToIndex({index: index + 1});
}
}
}}
hideArrow={hideArrow}
arrowColor={arrowColor}
arrowSize={arrowSize}
arrowAlign={arrowAlign}
/>;
};
/**
* See FlatList docs. If you'd like to do something outside. e.g: you maybe want to scroll to the end. Then you can
* use "<CalendarList ref={ref => this.calendarList = ref}; this.calendarList.scrollToEnd()" to make it work for you.
*/
scrollToIndex = params => this.flatList.scrollToIndex(params);
scrollToItem = params => this.flatList.scrollToItem(params);
scrollToOffset = params => this.flatList.scrollToOffset(params);
scrollToEnd = params => this.flatList.scrollToEnd(params);
render() {
const {
horizontal,
showsHorizontalScrollIndicator,
showsVerticalScrollIndicator,
scrollEnabled,
pagingEnabled,
containerStyle,
scrollContentStyle,
showToolBar,
toolBarPosition,
toolBarStyle,
toolBarCancelStyle,
toolBarConfirmStyle,
titleStyle,
titleText,
cancelText,
confirmText,
cancel,
confirm,
cancelDisabled,
confirmDisabled,
showWeeks,
weeks,
weeksChineseType,
firstDayOnWeeks,
weeksStyle,
weeksTextStyle,
} = this.props;
const _wks = weeksChineseType && weeks === Constants.DEFAULT_WEEK_EN ? Constants.DEFAULT_WEEK_ZH : weeks;
const _weeks = Constants.getWeekDays(_wks, firstDayOnWeeks);
const _toolBar = (<ToolBar
style={toolBarStyle}
cancelStyle={toolBarCancelStyle}
confirmStyle={toolBarConfirmStyle}
titleStyle={titleStyle}
titleText={titleText}
cancelText={cancelText}
cancel={() => cancel && typeof cancel === 'function' && cancel()}
confirm={() => {
const {startDate, endDate} = this.state;
const dates = [Constants.toStandardStringWith(startDate), Constants.toStandardStringWith(endDate)];
confirm && typeof confirm === 'function' && confirm(dates);
}}
confirmText={confirmText}
cancelDisabled={cancelDisabled}
confirmDisabled={confirmDisabled}
/>);
return (
<View style={containerStyle}>
{showToolBar && toolBarPosition === Constants.DEFAULT_TOOL_BAR_POSITION.TOP && _toolBar}
{showWeeks && !horizontal && <WeekBar
weeks={_weeks}
style={weeksStyle}
textStyle={weeksTextStyle}
/>}
<FlatList
style={scrollContentStyle}
automaticallyAdjustContentInsets={false}
ref={ref => this.flatList = ref}
keyExtractor={item => `${item.year}-${item.month}`}
data={this.state.dataSource}
extraData={this.state}
horizontal={horizontal}
showsHorizontalScrollIndicator={showsHorizontalScrollIndicator}
showsVerticalScrollIndicator={showsVerticalScrollIndicator}
scrollEnabled={scrollEnabled}
pagingEnabled={pagingEnabled}
initialNumToRender={5}
{...this.props}
renderItem={this._renderItem}
/>
{showToolBar && toolBarPosition === Constants.DEFAULT_TOOL_BAR_POSITION.BOTTOM && _toolBar}
</View>
);
}
}
CalendarList.propTypes = {
/**
* Seen as FlatList component.
*/
horizontal: PropTypes.bool,
/**
* Seen as FlatList component.
*/
showsHorizontalScrollIndicator: PropTypes.bool,
/**
* Seen as FlatList component.
*/
showsVerticalScrollIndicator: PropTypes.bool,
/**
* Seen as FlatList component. Default is true.
*/
scrollEnabled: PropTypes.bool,
/**
* Seen as FlatList component. Default is false.
*/
pagingEnabled: PropTypes.bool,
/**
* Styles for container, you can set it as any view prop styles such as {backgroundColor: 'red'}
*/
containerStyle: PropTypes.object,
/**
* Styles for scroll list - FlatList, you can set it as any view prop styles such as {backgroundColor: 'red'}
*/
scrollContentStyle: PropTypes.object,
/**
* Whether to show tool bar, default is true. If false, hide tool bar on top.
*/
showToolBar: PropTypes.bool,
/**
* The position of tool bar, default is 'top' that is at the top of screen. So far, just both 'top' and 'bottom'
* are supported.
*/
toolBarPosition: PropTypes.string,
/**
* tool bar view styles, passed like {backgroundColor: 'red'} as you like.
*/
toolBarStyle: PropTypes.object,
/**
* tool bar cancel button text styles, passed like {color: 'red', fontSize: 15} as you like.
* Note that you can control the active opacity of the button through {activeOpacity: 1}.
*/
toolBarCancelStyle: PropTypes.object,
/**
* tool bar confirm button text styles, passed like {color: 'red', fontSize: 15} as you like.
* Note that you can control the active opacity of the button through {activeOpacity: 1}.
*/
toolBarConfirmStyle: PropTypes.object,
/**
* tool bar title text style.
*/
titleStyle: PropTypes.object,
/**
* tool bar title text, default is "".
*/
titleText: PropTypes.string,
/**
* tool bar cancel button text, default is "Cancel".
*/
cancelText: PropTypes.string,
/**
* tool bar confirm button text, default is "Confirm".
*/
confirmText: PropTypes.string,
/**
* tool bar cancel button callback.
*/
cancel: PropTypes.func,
/**
* tool bar confirm button callback with a date array like ["2016-01-09", "2019-09-18"]. "2016-01-09" is the
* start date(min date) you selected. "2019-09-18" is the end date(max date) you selected. If nothing is selected,
* the array's elements will be empty string like ["", ""].
*/
confirm: PropTypes.func,
/**
* Whether to disable the cancel button. Default is false.
*/
cancelDisabled: PropTypes.bool,
/**
* Whether to disable the confirm button. Default is false.
*/
confirmDisabled: PropTypes.bool,
/**
* A callback with a date parameter(like "2019-08-09") and row index when the user presses some date item.
*/
onPressDate: PropTypes.func,
/**
* Min date to limit, default is "2000-01-01". Other supported formats: "2000-1-1", "2000/01/01", "2000/1/1".
* Note: Date type is also supported.
*/
minDate: PropTypes.oneOfType([
PropTypes.string,
PropTypes.instanceOf(Date),
]),
/**
* Max date to limit, default is today calculated by new Date(). Other supported formats: "2015-1-1", "2015/01/01", "2015/1/1".
* Note: Date type is also supported.
*/
maxDate: PropTypes.oneOfType([
PropTypes.string,
PropTypes.instanceOf(Date),
]),
/**
* The default dates for the initial selected values.
* Note: the count of defaultDates must be equal to 2. That is to say, you must pass two elements for it.
* Both string and Date type are also supported like minDate or maxDate above.
* For instance: defaultDates={['2015-10-10', '2020-01-01']} or defaultDates={['2015-10-10', new Date()]}.
* Attention! The first element must be greater than or equal to the minDate. The second element must be
* less than or equal to the maxDate. Or it will not work as you expected.
*/
defaultDates: PropTypes.arrayOf(
PropTypes.oneOfType([
PropTypes.string,
PropTypes.instanceOf(Date),
]),
),
/**
* Whether to show weeks, default is true.
*/
showWeeks: PropTypes.bool,
/**
* Week days to show, default is from Sunday to Saturday, namely ['Su','Mo','Tu','We','Th','Fr','Sa'].
* Note that if you want to custom "weeks", then you have to accomplish "firstDayOnWeeks" at the same time.
* For example, you passed "['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']" to "weeks", you must pass 1 to
* "firstDayOnWeeks" equal to "firstDayOnWeeks={1}". What's more, 1 means Monday, 2 means Tuesday, ..., 0 Means Sunday.
*/
weeks: PropTypes.array,
/**
* Weeks type. Default is false, namely ['Su','Mo','Tu','We','Th','Fr','Sa']. If you want to use chinese, such as
* ['日','一','二','三','四','五','六'], just setting "weeksChineseType={true}" is okay. But the precondition is that
* "weeks" above uses the default value. Or it will be invalid.
*/
weeksChineseType: PropTypes.bool,
/**
* The first day for weeks. Default is 0 equal to Sunday. If you'd like to start with Saturday, "firstDayOnWeeks={6}"
* will work. The value ranges from 0 to 6.
*/
firstDayOnWeeks: PropTypes.number,
/**
* For week days, set the container styles like {backgroundColor: 'red'}.
*/
weeksStyle: PropTypes.object,
/**
* For week days, set the week day text styles like {color: 'blue', fontSize: 14}.
*/
weeksTextStyle: PropTypes.object,
/**
* Display form of the header title. Default is 0. Take "2020-04" date as an example:
* 0: "2020-04"
* 1: "2020年4月"
* 2: "Apr 2020"
* 3: "April 2020"
* 4: "2020/04"
* 5: "04/2020"
*/
headerTitleType: PropTypes.number,
/**
* Content styles containing header title and days content. This is a nesting object style. So if you want to set
* some specific style such as "headerTitle", you can set it to {headerTitle: {fontSize: 18, color: 'red'}}. Details
* are as follows:
{
container: {
flex: 1,
},
headerTitleContainer: {
height: 50,
},
headerTitle: {
fontSize: 17,
},
dayContent: {
backgroundColor: 'red',
},
day: {
color: '#3e3e3e',
},
};
*/
listItemStyle: PropTypes.object,
/**
* Selected date mark type. Default is 'ellipse', other choices: 'semiellipse'、'rectangle'、'circle'、 'square'、'dot'.
*/
selectedDateMarkType: PropTypes.string,
/**
* Selected date mark background color for start date and end date. Default is 'magenta'.
*/
selectedDateMarkColor: PropTypes.string,
/**
* Selected date mark background color between start date and end date. Default is 'skyblue'.
*/
selectedDateMarkRangeColor: PropTypes.string,
/**
* When the date is out of minDate or maxDate, whether to disable the button. Default is true.
*/
beyondDatesDisabled: PropTypes.bool,
/**
* When the date is out of minDate or maxDate, the button text color. Default is '#b9b9b9'.
*/
beyondDatesDisabledTextColor: PropTypes.string,
/**
* Left arrow click callback with current date index parameter. Only when "horizontal={true}".
*/
leftArrowClick: PropTypes.func,
/**
* Right arrow click callback with current date index parameter. Only when "horizontal={true}".
*/
rightArrowClick: PropTypes.func,
/**
* Whether to hide arrow. Default is false. Only when "horizontal={true}".
*/
hideArrow: PropTypes.bool,
/**
* Arrow color. Default is 'gray'. Only when "horizontal={true}".
*/
arrowColor: PropTypes.string,
/**
* Arrow size. Default is 8. Only when "horizontal={true}".
*/
arrowSize: PropTypes.number,
/**
* Arrow align. Default is 'left'. One of ['left', 'center', 'right']. Only when "horizontal={true}".
*/
arrowAlign: PropTypes.string,
};
CalendarList.defaultProps = {
horizontal: false,
scrollEnabled: true,
pagingEnabled: false,
showToolBar: true,
toolBarPosition: Constants.DEFAULT_TOOL_BAR_POSITION.TOP,
cancelText: Constants.DEFAULT_CANCEL_TEXT,
confirmText: Constants.DEFAULT_CONFIRM_TEXT,
cancel: () => {
},
confirm: () => {
},
onPressDate: () => {
},
cancelDisabled: false,
confirmDisabled: false,
minDate: Constants.CALENDAR_DEFAULT_MIN_DATE,
maxDate: Constants.CALENDAR_DEFAULT_MAX_DATE,
showWeeks: true,
weeks: Constants.DEFAULT_WEEK_EN,
weeksChineseType: false,
firstDayOnWeeks: 0,
headerTitleType: 0,
listItemStyle: {},
selectedDateMarkType: Constants.DEFAULT_DATE_MARK_TYPE.ELLIPSE,
selectedDateMarkColor: 'magenta',
selectedDateMarkRangeColor: 'skyblue',
beyondDatesDisabled: true,
beyondDatesDisabledTextColor: '#b9b9b9',
};
export default CalendarList;