react-day-picker
Version:
Flexible date picker component for React
224 lines (201 loc) • 6.82 kB
JavaScript
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Weekdays from './Weekdays';
import Day from './Day';
import { ENTER } from './keys';
import * as ModifiersUtils from './ModifiersUtils';
import * as Helpers from './Helpers';
import * as DateUtils from './DateUtils';
export default class Month extends Component {
static propTypes = {
classNames: PropTypes.shape({
body: PropTypes.string.isRequired,
month: PropTypes.string.isRequired,
outside: PropTypes.string.isRequired,
today: PropTypes.string.isRequired,
week: PropTypes.string.isRequired,
weekNumber: PropTypes.string.isRequired,
disabled: PropTypes.string.isRequired,
selected: PropTypes.string.isRequired,
}).isRequired,
tabIndex: PropTypes.number,
month: PropTypes.instanceOf(Date).isRequired,
months: PropTypes.arrayOf(PropTypes.string),
modifiersStyles: PropTypes.object,
showWeekDays: PropTypes.bool,
showOutsideDays: PropTypes.bool,
renderDay: PropTypes.func.isRequired,
renderWeek: PropTypes.func.isRequired,
captionElement: PropTypes.oneOfType([
PropTypes.element,
PropTypes.func,
PropTypes.instanceOf(React.Component),
]).isRequired,
weekdayElement: PropTypes.oneOfType([
PropTypes.element,
PropTypes.func,
PropTypes.instanceOf(React.Component),
]),
fixedWeeks: PropTypes.bool,
showWeekNumbers: PropTypes.bool,
locale: PropTypes.string.isRequired,
localeUtils: PropTypes.object.isRequired,
weekdaysLong: PropTypes.arrayOf(PropTypes.string),
weekdaysShort: PropTypes.arrayOf(PropTypes.string),
firstDayOfWeek: PropTypes.number.isRequired,
onCaptionClick: PropTypes.func,
onDayClick: PropTypes.func,
onDayFocus: PropTypes.func,
onDayKeyDown: PropTypes.func,
onDayMouseEnter: PropTypes.func,
onDayMouseLeave: PropTypes.func,
onDayMouseDown: PropTypes.func,
onDayMouseUp: PropTypes.func,
onDayTouchEnd: PropTypes.func,
onDayTouchStart: PropTypes.func,
onWeekClick: PropTypes.func,
};
renderDay = day => {
const monthNumber = this.props.month.getMonth();
const propModifiers = Helpers.getModifiersFromProps(this.props);
const dayModifiers = ModifiersUtils.getModifiersForDay(day, propModifiers);
if (
DateUtils.isSameDay(day, new Date()) &&
!Object.prototype.hasOwnProperty.call(
propModifiers,
this.props.classNames.today
)
) {
dayModifiers.push(this.props.classNames.today);
}
if (day.getMonth() !== monthNumber) {
dayModifiers.push(this.props.classNames.outside);
}
const isOutside = day.getMonth() !== monthNumber;
let tabIndex = -1;
// Focus on the first day of the month
if (this.props.onDayClick && !isOutside && day.getDate() === 1) {
tabIndex = this.props.tabIndex; // eslint-disable-line prefer-destructuring
}
const key = `${day.getFullYear()}${day.getMonth()}${day.getDate()}`;
const modifiers = {};
dayModifiers.forEach(modifier => {
modifiers[modifier] = true;
});
return (
<Day
key={`${isOutside ? 'outside-' : ''}${key}`}
classNames={this.props.classNames}
day={day}
modifiers={modifiers}
modifiersStyles={this.props.modifiersStyles}
empty={
isOutside && !this.props.showOutsideDays && !this.props.fixedWeeks
}
tabIndex={tabIndex}
ariaLabel={this.props.localeUtils.formatDay(day, this.props.locale)}
ariaDisabled={
isOutside || dayModifiers.indexOf(this.props.classNames.disabled) > -1
}
ariaSelected={dayModifiers.indexOf(this.props.classNames.selected) > -1}
onClick={this.props.onDayClick}
onFocus={this.props.onDayFocus}
onKeyDown={this.props.onDayKeyDown}
onMouseEnter={this.props.onDayMouseEnter}
onMouseLeave={this.props.onDayMouseLeave}
onMouseDown={this.props.onDayMouseDown}
onMouseUp={this.props.onDayMouseUp}
onTouchEnd={this.props.onDayTouchEnd}
onTouchStart={this.props.onDayTouchStart}
>
{this.props.renderDay(day, modifiers)}
</Day>
);
};
render() {
const {
classNames,
month,
months,
fixedWeeks,
captionElement,
weekdayElement,
locale,
localeUtils,
weekdaysLong,
weekdaysShort,
firstDayOfWeek,
onCaptionClick,
showWeekNumbers,
showWeekDays,
onWeekClick,
} = this.props;
const captionProps = {
date: month,
classNames,
months,
localeUtils,
locale,
onClick: onCaptionClick ? e => onCaptionClick(month, e) : undefined,
};
const caption = React.isValidElement(captionElement)
? React.cloneElement(captionElement, captionProps)
: React.createElement(captionElement, captionProps);
const weeks = Helpers.getWeekArray(month, firstDayOfWeek, fixedWeeks);
return (
<div className={classNames.month} role="grid">
{caption}
{showWeekDays && (
<Weekdays
classNames={classNames}
weekdaysShort={weekdaysShort}
weekdaysLong={weekdaysLong}
firstDayOfWeek={firstDayOfWeek}
showWeekNumbers={showWeekNumbers}
locale={locale}
localeUtils={localeUtils}
weekdayElement={weekdayElement}
/>
)}
<div className={classNames.body} role="rowgroup">
{weeks.map(week => {
let weekNumber;
if (showWeekNumbers) {
weekNumber = DateUtils.getWeekNumber(week[6]);
}
return (
<div
key={week[0].getTime()}
className={classNames.week}
role="row"
>
{showWeekNumbers && (
<div
className={classNames.weekNumber}
tabIndex={onWeekClick ? 0 : -1}
role="gridcell"
onClick={
onWeekClick
? e => onWeekClick(weekNumber, week, e)
: undefined
}
onKeyUp={
onWeekClick
? e =>
e.keyCode === ENTER &&
onWeekClick(weekNumber, week, e)
: undefined
}
>
{this.props.renderWeek(weekNumber, week, month)}
</div>
)}
{week.map(this.renderDay)}
</div>
);
})}
</div>
</div>
);
}
}