Skip to content

Commit

Permalink
Add Year Picker variation (#2130)
Browse files Browse the repository at this point in the history
* add year picker variation

* removed rollup watch

* add tests

* add tests
  • Loading branch information
gautam-pahuja committed May 6, 2020
1 parent c4bdd55 commit 5f046b5
Show file tree
Hide file tree
Showing 13 changed files with 2,120 additions and 1,842 deletions.
5 changes: 5 additions & 0 deletions docs-site/src/components/Examples/index.js
Expand Up @@ -63,6 +63,7 @@ import RenderCustomDay from "../../examples/renderCustomDay";
import TimeInput from "../../examples/timeInput";
import StrictParsing from "../../examples/strictParsing";
import MonthPicker from "../../examples/monthPicker";
import YearPicker from "../../examples/yearPicker";
import monthPickerFullName from "../../examples/monthPickerFullName";
import RangeMonthPicker from "../../examples/rangeMonthPicker";
import QuarterPicker from "../../examples/quarterPicker";
Expand Down Expand Up @@ -320,6 +321,10 @@ export default class exampleComponents extends React.Component {
title: "Month Picker",
component: MonthPicker
},
{
title: "Year Picker",
component: YearPicker
},
{
title: "Month Picker with Full Name",
component: monthPickerFullName
Expand Down
11 changes: 11 additions & 0 deletions docs-site/src/examples/yearPicker.js
@@ -0,0 +1,11 @@
() => {
const [startDate, setStartDate] = useState(new Date());
return (
<DatePicker
selected={startDate}
onChange={date => setStartDate(date)}
showYearPicker
dateFormat="yyyy"
/>
);
};
3 changes: 2 additions & 1 deletion package.json
Expand Up @@ -131,7 +131,8 @@
"css:modules:prod": "node-sass --output-style compressed src/stylesheets/datepicker-cssmodules.scss > dist/react-datepicker-cssmodules.min.css",
"css:dev": "node-sass --output-style expanded src/stylesheets/datepicker.scss > dist/react-datepicker.css",
"css:modules:dev": "node-sass --output-style expanded src/stylesheets/datepicker-cssmodules.scss > dist/react-datepicker-cssmodules.css",
"build:js": "rollup -c"
"build:js": "rollup -c",
"js:dev": "rollup -cw"
},
"lint-staged": {
"*.{js,jsx,json,css,scss,md}": [
Expand Down
44 changes: 37 additions & 7 deletions src/calendar.jsx
Expand Up @@ -3,6 +3,7 @@ import MonthDropdown from "./month_dropdown";
import MonthYearDropdown from "./month_year_dropdown";
import Month from "./month";
import Time from "./time";
import Year from "./year";
import InputTime from "./inputTime";
import React from "react";
import PropTypes from "prop-types";
Expand Down Expand Up @@ -112,6 +113,7 @@ export default class Calendar extends React.Component {
showTimeInput: PropTypes.bool,
showMonthYearPicker: PropTypes.bool,
showFullMonthYearPicker: PropTypes.bool,
showYearPicker: PropTypes.bool,
showQuarterYearPicker: PropTypes.bool,
showTimeSelectOnly: PropTypes.bool,
timeFormat: PropTypes.string,
Expand Down Expand Up @@ -375,7 +377,7 @@ export default class Calendar extends React.Component {
decreaseYear = () => {
this.setState(
({ date }) => ({
date: subYears(date, 1)
date: subYears(date, this.props.showYearPicker ? 11 : 1)
}),
() => this.handleYearChange(this.state.date)
);
Expand Down Expand Up @@ -406,7 +408,11 @@ export default class Calendar extends React.Component {

let clickHandler = this.decreaseMonth;

if (this.props.showMonthYearPicker || this.props.showQuarterYearPicker) {
if (
this.props.showMonthYearPicker ||
this.props.showQuarterYearPicker ||
this.props.showYearPicker
) {
clickHandler = this.decreaseYear;
}

Expand Down Expand Up @@ -440,7 +446,7 @@ export default class Calendar extends React.Component {
increaseYear = () => {
this.setState(
({ date }) => ({
date: addYears(date, 1)
date: addYears(date, this.props.showYearPicker ? 11 : 1)
}),
() => this.handleYearChange(this.state.date)
);
Expand Down Expand Up @@ -477,7 +483,11 @@ export default class Calendar extends React.Component {

let clickHandler = this.increaseMonth;

if (this.props.showMonthYearPicker || this.props.showQuarterYearPicker) {
if (
this.props.showMonthYearPicker ||
this.props.showQuarterYearPicker ||
this.props.showYearPicker
) {
clickHandler = this.increaseYear;
}

Expand Down Expand Up @@ -665,7 +675,9 @@ export default class Calendar extends React.Component {
renderYearHeader = () => {
return (
<div className="react-datepicker__header react-datepicker-year-header">
{getYear(this.state.date)}
{this.props.showYearPicker
? `${getYear(this.state.date) - 11} - ${getYear(this.state.date)}`
: getYear(this.state.date)}
</div>
);
};
Expand All @@ -674,15 +686,17 @@ export default class Calendar extends React.Component {
switch (true) {
case this.props.renderCustomHeader !== undefined:
return this.renderCustomHeader(headerArgs);
case this.props.showMonthYearPicker || this.props.showQuarterYearPicker:
case this.props.showMonthYearPicker ||
this.props.showQuarterYearPicker ||
this.props.showYearPicker:
return this.renderYearHeader(headerArgs);
default:
return this.renderDefaultHeader(headerArgs);
}
};

renderMonths = () => {
if (this.props.showTimeSelectOnly) {
if (this.props.showTimeSelectOnly || this.props.showYearPicker) {
return;
}

Expand Down Expand Up @@ -743,6 +757,7 @@ export default class Calendar extends React.Component {
disabledKeyboardNavigation={this.props.disabledKeyboardNavigation}
showMonthYearPicker={this.props.showMonthYearPicker}
showFullMonthYearPicker={this.props.showFullMonthYearPicker}
showYearPicker={this.props.showYearPicker}
showQuarterYearPicker={this.props.showQuarterYearPicker}
isInputFocused={this.props.isInputFocused}
containerRef={this.containerRef}
Expand All @@ -753,6 +768,20 @@ export default class Calendar extends React.Component {
return monthList;
};

renderYears = () => {
if (this.props.showTimeSelectOnly) {
return;
}
if (this.props.showYearPicker) {
return (
<div className="react-datepicker__year">
{this.renderHeader()}
<Year onDayClick={this.handleDayClick} date={this.state.date} />
</div>
);
}
};

renderTimeSection = () => {
if (
this.props.showTimeSelect &&
Expand Down Expand Up @@ -814,6 +843,7 @@ export default class Calendar extends React.Component {
{this.renderPreviousButton()}
{this.renderNextButton()}
{this.renderMonths()}
{this.renderYears()}
{this.renderTodayButton()}
{this.renderTimeSection()}
{this.renderInputTimeSection()}
Expand Down
8 changes: 7 additions & 1 deletion src/date_utils.js
Expand Up @@ -192,7 +192,9 @@ export {
};

export function getWeek(date, locale) {
let localeObj = (locale && getLocaleObject(locale)) || (getDefaultLocale() && getLocaleObject(getDefaultLocale()));
let localeObj =
(locale && getLocaleObject(locale)) ||
(getDefaultLocale() && getLocaleObject(getDefaultLocale()));
return dfgetWeek(date, localeObj ? { locale: localeObj } : null);
}

Expand All @@ -217,6 +219,10 @@ export function getStartOfMonth(date) {
return startOfMonth(date);
}

export function getStartOfYear(date) {
return startOfYear(date);
}

export function getStartOfQuarter(date) {
return startOfQuarter(date);
}
Expand Down
3 changes: 3 additions & 0 deletions src/index.jsx
Expand Up @@ -90,6 +90,7 @@ export default class DatePicker extends React.Component {
showPreviousMonths: false,
showMonthYearPicker: false,
showFullMonthYearPicker: false,
showYearPicker: false,
showQuarterYearPicker: false,
strictParsing: false,
timeIntervals: 30,
Expand Down Expand Up @@ -211,6 +212,7 @@ export default class DatePicker extends React.Component {
showTimeInput: PropTypes.bool,
showMonthYearPicker: PropTypes.bool,
showFullMonthYearPicker: PropTypes.bool,
showYearPicker: PropTypes.bool,
showQuarterYearPicker: PropTypes.bool,
showTimeSelect: PropTypes.bool,
showTimeSelectOnly: PropTypes.bool,
Expand Down Expand Up @@ -804,6 +806,7 @@ export default class DatePicker extends React.Component {
showTimeInput={this.props.showTimeInput}
showMonthYearPicker={this.props.showMonthYearPicker}
showFullMonthYearPicker={this.props.showFullMonthYearPicker}
showYearPicker={this.props.showYearPicker}
showQuarterYearPicker={this.props.showQuarterYearPicker}
showPopperArrow={this.props.showPopperArrow}
excludeScrollbar={this.props.excludeScrollbar}
Expand Down
18 changes: 17 additions & 1 deletion src/stylesheets/datepicker.scss
Expand Up @@ -51,7 +51,7 @@
@extend %triangle-arrow-up;
}
}

&[data-placement="bottom-end"],
&[data-placement="top-end"] {
.react-datepicker__triangle {
Expand Down Expand Up @@ -208,6 +208,22 @@
float: left;
}

.react-datepicker__year {
&-container {
margin: $datepicker__margin;
text-align: center;
display: flex;
flex-wrap: wrap;
&-text {
display: inline-block;
cursor: pointer;
flex: 1 0 30%;
width: 12px;
padding: 2px;
}
}
}

.react-datepicker__month {
margin: $datepicker__margin;
text-align: center;
Expand Down
52 changes: 52 additions & 0 deletions src/year.jsx
@@ -0,0 +1,52 @@
import React from "react";
import PropTypes from "prop-types";
import { getYear } from "./date_utils";
import * as utils from "./date_utils";

export default class Year extends React.Component {
static propTypes = {
date: PropTypes.string,
onDayClick: PropTypes.func
};

constructor(props) {
super(props);
}

handleYearClick = (day, event) => {
if (this.props.onDayClick) {
this.props.onDayClick(day, event);
}
};

onYearClick = (e, y) => {
this.handleYearClick(
utils.getStartOfYear(utils.setYear(this.props.date, y)),
e
);
};

render() {
const yearsToShow = 11;
const yearsList = [];
const { date } = this.props;
for (
let y = getYear(date) - yearsToShow, i = 0;
y <= getYear(date);
y++, i++
) {
yearsList.push(
<div
onClick={ev => {
this.onYearClick(ev, y);
}}
className="react-datepicker__year-container-text"
key={y}
>
{y}
</div>
);
}
return <div className="react-datepicker__year-container">{yearsList}</div>;
}
}
47 changes: 47 additions & 0 deletions test/calendar_test.js
Expand Up @@ -1064,6 +1064,53 @@ describe("Calendar", function() {
});
});

describe("renderYearPicker", function() {
it("should render YearPicker component", function() {
let calendar = mount(
<Calendar
dateFormat={dateFormat}
onSelect={() => {}}
onClickOutside={() => {}}
hideCalendar={() => {}}
dropdownMode="select"
showYearPicker
/>
);
const timeInputClassname = calendar.find(".react-datepicker__year");
expect(timeInputClassname).to.have.length(1);
});

it("calls increaseYear when next year button clicked", () => {
var calendar = TestUtils.renderIntoDocument(
<Calendar
dateFormat={DATE_FORMAT}
onSelect={() => {}}
onClickOutside={() => {}}
showYearPicker
/>
);
calendar.state.date = utils.parseDate("09/28/1993", DATE_FORMAT);
var increaseYear = calendar.increaseYear;
increaseYear();
assert.equal(utils.getYear(calendar.state.date), 2004);
});

it("calls decreaseYear when previous year button clicked", () => {
var calendar = TestUtils.renderIntoDocument(
<Calendar
dateFormat={DATE_FORMAT}
onSelect={() => {}}
onClickOutside={() => {}}
showYearPicker
/>
);
calendar.state.date = utils.parseDate("09/28/1993", DATE_FORMAT);
var decreaseYear = calendar.decreaseYear;
decreaseYear();
assert.equal(utils.getYear(calendar.state.date), 1982);
});
});

describe("when showMonthYearPicker is enabled", () => {
let calendar = mount(
<Calendar
Expand Down
11 changes: 10 additions & 1 deletion test/date_utils_test.js
Expand Up @@ -22,7 +22,8 @@ import {
isDayInRange,
parseDate,
isMonthinRange,
isQuarterInRange
isQuarterInRange,
getStartOfYear
} from "../src/date_utils";
import setMinutes from "date-fns/setMinutes";
import setHours from "date-fns/setHours";
Expand Down Expand Up @@ -690,6 +691,14 @@ describe("date_utils", function() {
});
});

describe("getStartOfYear", () => {
it("should return the start of the year", () => {
const day = new Date("2020-04-13T00:00:00.000+08:00");
expect(getStartOfYear(day).getDate()).to.be.eq(1);
expect(getStartOfYear(day).getMonth()).to.be.eq(0);
});
});

describe("isQuarterInRange", () => {
it("should return true if the quarter passed is in range", () => {
const day = newDate("2015-02-01");
Expand Down
2 changes: 1 addition & 1 deletion test/time_input_test.js
Expand Up @@ -4,7 +4,7 @@ import DatePicker from "../src/index.jsx";
import InputTimeComponent from "../src/inputTime";
import PropTypes from "prop-types";

describe("DatePicker", () => {
describe("timeInput", () => {
let sandbox;

beforeEach(() => {
Expand Down

0 comments on commit 5f046b5

Please sign in to comment.