Skip to content

Commit 3c1de28

Browse files
gautam-pahujamartijnrusschen
authored andcommitted
Month year picker (#1680)
* add basic month picker * Added new option of Month/Year picker * Add tests
1 parent 9409a0e commit 3c1de28

File tree

10 files changed

+2089
-765
lines changed

10 files changed

+2089
-765
lines changed

docs-site/bundle.js

Lines changed: 1807 additions & 722 deletions
Large diffs are not rendered by default.

docs-site/src/example_components.jsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ import RenderCustomHeader from "./examples/render_custom_header";
5555
import RenderCustomDay from "./examples/render_custom_day";
5656
import TimeInput from "./examples/timeInput";
5757
import StrictParsing from "./examples/strict_parsing";
58+
import MonthPicker from "./examples/month_picker";
5859
import "react-datepicker/dist/react-datepicker.css";
5960
import "./style.scss";
6061

@@ -275,6 +276,10 @@ export default class exampleComponents extends React.Component {
275276
{
276277
title: "Strict parsing",
277278
component: <StrictParsing />
279+
},
280+
{
281+
title: "Month Picker",
282+
component: <MonthPicker />
278283
}
279284
];
280285

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import React from "react";
2+
import DatePicker from "react-datepicker";
3+
4+
export default class MonthPicker extends React.Component {
5+
constructor(props) {
6+
super(props);
7+
this.state = {
8+
startDate: new Date()
9+
};
10+
}
11+
12+
handleChange = date => {
13+
this.setState({
14+
startDate: date
15+
});
16+
};
17+
18+
render() {
19+
return (
20+
<div className="row">
21+
<pre className="column example__code">
22+
<code className="jsx">
23+
{`
24+
<DatePicker
25+
selected={this.state.startDate}
26+
onChange={this.handleChange}
27+
dateFormat="MM/yyyy"
28+
showMonthYearPicker
29+
/>
30+
`}
31+
</code>
32+
</pre>
33+
<div className="column">
34+
<DatePicker
35+
selected={this.state.startDate}
36+
onChange={this.handleChange}
37+
dateFormat="MM/yyyy"
38+
showMonthYearPicker
39+
/>
40+
</div>
41+
</div>
42+
);
43+
}
44+
}

docs-site/style.css

Lines changed: 40 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,8 @@
168168
}
169169

170170
.react-datepicker__current-month,
171-
.react-datepicker-time__header {
171+
.react-datepicker-time__header,
172+
.react-datepicker-year-header {
172173
margin-top: 0;
173174
color: #000;
174175
font-weight: bold;
@@ -254,6 +255,10 @@
254255
margin: 0.4rem;
255256
text-align: center;
256257
}
258+
.react-datepicker__month .react-datepicker__month-text {
259+
display: inline-block;
260+
width: 4rem;
261+
}
257262

258263
.react-datepicker__input-time-container {
259264
clear: both;
@@ -423,63 +428,82 @@
423428
margin: 0.166rem;
424429
}
425430

426-
.react-datepicker__day {
431+
.react-datepicker__day,
432+
.react-datepicker__month-text {
427433
cursor: pointer;
428434
}
429-
.react-datepicker__day:hover {
435+
.react-datepicker__day:hover,
436+
.react-datepicker__month-text:hover {
430437
border-radius: 0.3rem;
431438
background-color: #f0f0f0;
432439
}
433-
.react-datepicker__day--today {
440+
.react-datepicker__day--today,
441+
.react-datepicker__month-text--today {
434442
font-weight: bold;
435443
}
436-
.react-datepicker__day--highlighted {
444+
.react-datepicker__day--highlighted,
445+
.react-datepicker__month-text--highlighted {
437446
border-radius: 0.3rem;
438447
background-color: #3dcc4a;
439448
color: #fff;
440449
}
441-
.react-datepicker__day--highlighted:hover {
450+
.react-datepicker__day--highlighted:hover,
451+
.react-datepicker__month-text--highlighted:hover {
442452
background-color: #32be3f;
443453
}
444-
.react-datepicker__day--highlighted-custom-1 {
454+
.react-datepicker__day--highlighted-custom-1,
455+
.react-datepicker__month-text--highlighted-custom-1 {
445456
color: magenta;
446457
}
447-
.react-datepicker__day--highlighted-custom-2 {
458+
.react-datepicker__day--highlighted-custom-2,
459+
.react-datepicker__month-text--highlighted-custom-2 {
448460
color: green;
449461
}
450462
.react-datepicker__day--selected,
451463
.react-datepicker__day--in-selecting-range,
452-
.react-datepicker__day--in-range {
464+
.react-datepicker__day--in-range,
465+
.react-datepicker__month-text--selected,
466+
.react-datepicker__month-text--in-selecting-range,
467+
.react-datepicker__month-text--in-range {
453468
border-radius: 0.3rem;
454469
background-color: #216ba5;
455470
color: #fff;
456471
}
457472
.react-datepicker__day--selected:hover,
458473
.react-datepicker__day--in-selecting-range:hover,
459-
.react-datepicker__day--in-range:hover {
474+
.react-datepicker__day--in-range:hover,
475+
.react-datepicker__month-text--selected:hover,
476+
.react-datepicker__month-text--in-selecting-range:hover,
477+
.react-datepicker__month-text--in-range:hover {
460478
background-color: #1d5d90;
461479
}
462-
.react-datepicker__day--keyboard-selected {
480+
.react-datepicker__day--keyboard-selected,
481+
.react-datepicker__month-text--keyboard-selected {
463482
border-radius: 0.3rem;
464483
background-color: #2a87d0;
465484
color: #fff;
466485
}
467-
.react-datepicker__day--keyboard-selected:hover {
486+
.react-datepicker__day--keyboard-selected:hover,
487+
.react-datepicker__month-text--keyboard-selected:hover {
468488
background-color: #1d5d90;
469489
}
470-
.react-datepicker__day--in-selecting-range:not(.react-datepicker__day--in-range) {
490+
.react-datepicker__day--in-selecting-range,
491+
.react-datepicker__month-text--in-selecting-range {
471492
background-color: rgba(33, 107, 165, 0.5);
472493
}
494+
.react-datepicker__month--selecting-range .react-datepicker__day--in-range,
473495
.react-datepicker__month--selecting-range
474-
.react-datepicker__day--in-range:not(.react-datepicker__day--in-selecting-range) {
496+
.react-datepicker__month-text--in-range {
475497
background-color: #f0f0f0;
476498
color: #000;
477499
}
478-
.react-datepicker__day--disabled {
500+
.react-datepicker__day--disabled,
501+
.react-datepicker__month-text--disabled {
479502
cursor: default;
480503
color: #ccc;
481504
}
482-
.react-datepicker__day--disabled:hover {
505+
.react-datepicker__day--disabled:hover,
506+
.react-datepicker__month-text--disabled:hover {
483507
background-color: transparent;
484508
}
485509

src/calendar.jsx

Lines changed: 58 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import {
2121
setYear,
2222
getYear,
2323
isBefore,
24+
addYears,
25+
subYears,
2426
isAfter,
2527
getFormattedWeekdayInLocale,
2628
getWeekdayShortInLocale,
@@ -84,6 +86,7 @@ export default class Calendar extends React.Component {
8486
onWeekSelect: PropTypes.func,
8587
showTimeSelect: PropTypes.bool,
8688
showTimeInput: PropTypes.bool,
89+
showMonthYearPicker: PropTypes.bool,
8790
showTimeSelectOnly: PropTypes.bool,
8891
timeFormat: PropTypes.string,
8992
timeIntervals: PropTypes.number,
@@ -118,6 +121,8 @@ export default class Calendar extends React.Component {
118121
showDisabledMonthNavigation: PropTypes.bool,
119122
previousMonthButtonLabel: PropTypes.string,
120123
nextMonthButtonLabel: PropTypes.string,
124+
previousYearButtonLabel: PropTypes.string,
125+
nextYearButtonLabel: PropTypes.string,
121126
renderCustomHeader: PropTypes.func,
122127
renderDayContents: PropTypes.func,
123128
onDayMouseEnter: PropTypes.func,
@@ -131,6 +136,8 @@ export default class Calendar extends React.Component {
131136
monthSelectedIn: 0,
132137
forceShowMonthNavigation: false,
133138
timeCaption: "Time",
139+
previousYearButtonLabel: "Previous Year",
140+
nextYearButtonLabel: "Next Year",
134141
previousMonthButtonLabel: "Previous Month",
135142
nextMonthButtonLabel: "Next Month"
136143
};
@@ -322,7 +329,16 @@ export default class Calendar extends React.Component {
322329
: getWeekdayMinInLocale(day, locale);
323330
};
324331

325-
renderPreviousMonthButton = () => {
332+
decreaseYear = () => {
333+
this.setState(
334+
{
335+
date: subYears(this.state.date, 1)
336+
},
337+
() => this.handleYearChange(this.state.date)
338+
);
339+
};
340+
341+
renderPreviousButton = () => {
326342
if (this.props.renderCustomHeader) {
327343
return;
328344
}
@@ -348,6 +364,10 @@ export default class Calendar extends React.Component {
348364

349365
let clickHandler = this.decreaseMonth;
350366

367+
if (this.props.showMonthYearPicker) {
368+
clickHandler = this.decreaseYear;
369+
}
370+
351371
if (allPrevDaysDisabled && this.props.showDisabledMonthNavigation) {
352372
classes.push("react-datepicker__navigation--previous--disabled");
353373
clickHandler = null;
@@ -359,12 +379,23 @@ export default class Calendar extends React.Component {
359379
className={classes.join(" ")}
360380
onClick={clickHandler}
361381
>
362-
{this.props.previousMonthButtonLabel}
382+
{this.props.showMonthYearPicker
383+
? this.props.previousYearButtonLabel
384+
: this.props.previousMonthButtonLabel}
363385
</button>
364386
);
365387
};
366388

367-
renderNextMonthButton = () => {
389+
increaseYear = () => {
390+
this.setState(
391+
{
392+
date: addYears(this.state.date, 1)
393+
},
394+
() => this.handleYearChange(this.state.date)
395+
);
396+
};
397+
398+
renderNextButton = () => {
368399
if (this.props.renderCustomHeader) {
369400
return;
370401
}
@@ -393,6 +424,10 @@ export default class Calendar extends React.Component {
393424

394425
let clickHandler = this.increaseMonth;
395426

427+
if (this.props.showMonthYearPicker) {
428+
clickHandler = this.increaseYear;
429+
}
430+
396431
if (allNextDaysDisabled && this.props.showDisabledMonthNavigation) {
397432
classes.push("react-datepicker__navigation--next--disabled");
398433
clickHandler = null;
@@ -404,7 +439,9 @@ export default class Calendar extends React.Component {
404439
className={classes.join(" ")}
405440
onClick={clickHandler}
406441
>
407-
{this.props.nextMonthButtonLabel}
442+
{this.props.showMonthYearPicker
443+
? this.props.nextYearButtonLabel
444+
: this.props.nextMonthButtonLabel}
408445
</button>
409446
);
410447
};
@@ -551,6 +588,14 @@ export default class Calendar extends React.Component {
551588
);
552589
};
553590

591+
renderYearHeader = () => {
592+
return (
593+
<div className="react-datepicker__header react-datepicker-year-header">
594+
{getYear(this.state.date)}
595+
</div>
596+
);
597+
};
598+
554599
renderMonths = () => {
555600
if (this.props.showTimeSelectOnly) {
556601
return;
@@ -569,10 +614,13 @@ export default class Calendar extends React.Component {
569614
}}
570615
className="react-datepicker__month-container"
571616
>
572-
{this.props.renderCustomHeader
573-
? this.renderCustomHeader({ monthDate, i })
574-
: this.renderDefaultHeader({ monthDate, i })}
617+
{!this.props.showMonthYearPicker
618+
? this.props.renderCustomHeader
619+
? this.renderCustomHeader({ monthDate, i })
620+
: this.renderDefaultHeader({ monthDate, i })
621+
: this.renderYearHeader({ monthDate, i })}
575622
<Month
623+
onChange={this.changeMonthYear}
576624
day={monthDate}
577625
dayClassName={this.props.dayClassName}
578626
onDayClick={this.handleDayClick}
@@ -603,6 +651,7 @@ export default class Calendar extends React.Component {
603651
shouldCloseOnSelect={this.props.shouldCloseOnSelect}
604652
renderDayContents={this.props.renderDayContents}
605653
disabledKeyboardNavigation={this.props.disabledKeyboardNavigation}
654+
showMonthYearPicker={this.props.showMonthYearPicker}
606655
/>
607656
</div>
608657
);
@@ -662,8 +711,8 @@ export default class Calendar extends React.Component {
662711
"react-datepicker--time-only": this.props.showTimeSelectOnly
663712
})}
664713
>
665-
{this.renderPreviousMonthButton()}
666-
{this.renderNextMonthButton()}
714+
{this.renderPreviousButton()}
715+
{this.renderNextButton()}
667716
{this.renderMonths()}
668717
{this.renderTodayButton()}
669718
{this.renderTimeSection()}

0 commit comments

Comments
 (0)