UNPKG

react-calendar-custom-date

Version:

A React component for choosing dates and date ranges.

247 lines (235 loc) 7.47 kB
/* eslint-disable no-fallthrough */ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import classnames from 'classnames'; import { startOfDay, format, isSameDay, isAfter, isBefore, endOfDay } from 'date-fns'; class DayCell extends Component { constructor(props, context) { super(props, context); this.state = { hover: false, active: false, }; this.getClassNames = this.getClassNames.bind(this); this.handleMouseEvent = this.handleMouseEvent.bind(this); this.handleKeyEvent = this.handleKeyEvent.bind(this); this.renderSelectionPlaceholders = this.renderSelectionPlaceholders.bind(this); this.renderPreviewPlaceholder = this.renderPreviewPlaceholder.bind(this); } handleKeyEvent(event) { const { day } = this.props; switch (event.keyCode) { case 13: //space case 32: //enter if (event.type === 'keydown') { this.props.onMouseDown(day); } else { this.props.onMouseUp(day); } break; } } handleMouseEvent(event) { const { day, disabled, onPreviewChange } = this.props; const stateChanges = {}; if (disabled) { onPreviewChange(); return; } switch (event.type) { case 'mouseenter': this.props.onMouseEnter(day); onPreviewChange(day); stateChanges.hover = true; break; case 'blur': case 'mouseleave': stateChanges.hover = false; break; case 'mousedown': stateChanges.active = true; this.props.onMouseDown(day); break; case 'mouseup': event.stopPropagation(); stateChanges.active = false; this.props.onMouseUp(day); break; case 'focus': onPreviewChange(day); break; } if (Object.keys(stateChanges).length) { this.setState(stateChanges); } } getClassNames() { const { isPassive, isToday, isWeekend, isStartOfWeek, isEndOfWeek, isStartOfMonth, isEndOfMonth, disabled, styles, } = this.props; return classnames(styles.day, { [styles.dayPassive]: isPassive, [styles.dayDisabled]: disabled, [styles.dayToday]: isToday, [styles.dayWeekend]: isWeekend, [styles.dayStartOfWeek]: isStartOfWeek, [styles.dayEndOfWeek]: isEndOfWeek, [styles.dayStartOfMonth]: isStartOfMonth, [styles.dayEndOfMonth]: isEndOfMonth, [styles.dayHovered]: this.state.hover, [styles.dayActive]: this.state.active, }); } renderPreviewPlaceholder() { const { preview, day, styles } = this.props; if (!preview) return null; const startDate = preview.startDate ? endOfDay(preview.startDate) : null; const endDate = preview.endDate ? startOfDay(preview.endDate) : null; const isInRange = (!startDate || isAfter(day, startDate)) && (!endDate || isBefore(day, endDate)); const isStartEdge = !isInRange && isSameDay(day, startDate); const isEndEdge = !isInRange && isSameDay(day, endDate); return ( <span className={classnames({ [styles.dayStartPreview]: isStartEdge, [styles.dayInPreview]: isInRange, [styles.dayEndPreview]: isEndEdge, })} style={{ color: preview.color }} /> ); } renderSelectionPlaceholders() { const { styles, ranges, day } = this.props; if (this.props.displayMode === 'date') { let isSelected = isSameDay(this.props.day, this.props.date); return isSelected ? ( <span className={styles.selected} style={{ color: this.props.color }} /> ) : null; } const inRanges = ranges.reduce((result, range) => { let startDate = range.startDate; let endDate = range.endDate; if (startDate && endDate && isBefore(endDate, startDate)) { [startDate, endDate] = [endDate, startDate]; } startDate = startDate ? endOfDay(startDate) : null; endDate = endDate ? startOfDay(endDate) : null; const isInRange = (!startDate || isAfter(day, startDate)) && (!endDate || isBefore(day, endDate)); const isStartEdge = !isInRange && isSameDay(day, startDate); const isEndEdge = !isInRange && isSameDay(day, endDate); if (isInRange || isStartEdge || isEndEdge) { return [ ...result, { isStartEdge, isEndEdge: isEndEdge, isInRange, ...range, }, ]; } return result; }, []); return inRanges.map((range, i) => ( <span key={i} className={classnames({ [styles.startEdge]: range.isStartEdge, [styles.endEdge]: range.isEndEdge, [styles.inRange]: range.isInRange, })} style={{ color: range.color || this.props.color }} /> )); } render() { const { styles, cellInfoClassName, cellInfo } = this.props; let dayInfo = []; if (this.props && this.props !== 'undefined' && cellInfo) { dayInfo = this.props.cellInfo.filter(data => { return isSameDay(new Date(data.date), new Date(this.props.day)); }); } return ( <button type="button" onMouseEnter={this.handleMouseEvent} onMouseLeave={this.handleMouseEvent} onFocus={this.handleMouseEvent} onMouseDown={this.handleMouseEvent} onMouseUp={this.handleMouseEvent} onBlur={this.handleMouseEvent} onPauseCapture={this.handleMouseEvent} onKeyDown={this.handleKeyEvent} onKeyUp={this.handleKeyEvent} className={this.getClassNames(styles)} {...(this.props.disabled || this.props.isPassive ? { tabIndex: -1 } : {})} style={{ color: this.props.color }}> {this.renderSelectionPlaceholders()} {this.renderPreviewPlaceholder()} <span className={ dayInfo.length > 0 ? `${styles.dayNumber} cell-info-wrapper` : styles.dayNumber }> <span>{format(this.props.day, 'D')}</span> {dayInfo.length > 0 && ( <span className={cellInfoClassName} style={{ display: 'inline-block', marginTop: '15px' }}> {dayInfo[0].value} </span> )} </span> </button> ); } } DayCell.defaultProps = {}; export const rangeShape = PropTypes.shape({ startDate: PropTypes.object, endDate: PropTypes.object, color: PropTypes.string, key: PropTypes.string, autoFocus: PropTypes.bool, disabled: PropTypes.bool, showDateDisplay: PropTypes.bool, }); DayCell.propTypes = { day: PropTypes.object.isRequired, date: PropTypes.object, ranges: PropTypes.arrayOf(rangeShape), preview: PropTypes.shape({ startDate: PropTypes.object, endDate: PropTypes.object, }), onPreviewChange: PropTypes.func, previewColor: PropTypes.string, disabled: PropTypes.bool, isPassive: PropTypes.bool, isToday: PropTypes.bool, isWeekend: PropTypes.bool, isStartOfWeek: PropTypes.bool, isEndOfWeek: PropTypes.bool, isStartOfMonth: PropTypes.bool, isEndOfMonth: PropTypes.bool, color: PropTypes.string, displayMode: PropTypes.oneOf(['dateRange', 'date']), styles: PropTypes.object, onMouseDown: PropTypes.func, onMouseUp: PropTypes.func, onMouseEnter: PropTypes.func, cellInfo: PropTypes.array, cellInfoClassName: PropTypes.string, }; export default DayCell;