diff --git a/docs-site/src/components/Examples/index.js b/docs-site/src/components/Examples/index.js index fef9e6f2f..b7120c0eb 100644 --- a/docs-site/src/components/Examples/index.js +++ b/docs-site/src/components/Examples/index.js @@ -105,6 +105,7 @@ import SelectsMultiple from "../../examples/selectsMultiple"; import CalendarIconExternal from "../../examples/calendarIconExternal"; import CalendarIconSvgIcon from "../../examples/calendarIconSvgIcon"; import ToggleCalendarOnIconClick from "../../examples/toggleCalendarOnIconClick"; +import SwapRange from "../../examples/rangeSwapRange"; import "./style.scss"; import "react-datepicker/dist/react-datepicker.css"; @@ -461,6 +462,12 @@ export default class exampleComponents extends React.Component { title: "Range Quarter Picker for one quarter picker", component: RangeQuarterPickerSelectsRange, }, + { + title: "Range Swap Range", + description: + "Swap the start and end date if the end date is before the start date in a pick sequence.", + component: SwapRange, + }, { title: "Read only datepicker", component: ReadOnly, diff --git a/docs-site/src/examples/rangeSwapRange.js b/docs-site/src/examples/rangeSwapRange.js new file mode 100644 index 000000000..d78e30da3 --- /dev/null +++ b/docs-site/src/examples/rangeSwapRange.js @@ -0,0 +1,22 @@ +() => { + const [startDate, setStartDate] = useState(new Date()); + const [endDate, setEndDate] = useState(null); + const onChange = (dates) => { + const [start, end] = dates; + setStartDate(start); + setEndDate(end); + }; + return ( + + ); +}; diff --git a/src/index.jsx b/src/index.jsx index 03d84ba3f..5168b25d3 100644 --- a/src/index.jsx +++ b/src/index.jsx @@ -115,6 +115,7 @@ export default class DatePicker extends React.Component { showQuarterYearPicker: false, showWeekPicker: false, strictParsing: false, + swapRange: false, timeIntervals: 30, timeCaption: "Time", previousMonthAriaLabel: "Previous Month", @@ -253,6 +254,7 @@ export default class DatePicker extends React.Component { showWeekNumbers: PropTypes.bool, showYearDropdown: PropTypes.bool, strictParsing: PropTypes.bool, + swapRange: PropTypes.bool, forceShowMonthNavigation: PropTypes.bool, showDisabledMonthNavigation: PropTypes.bool, startDate: PropTypes.instanceOf(Date), @@ -634,6 +636,7 @@ export default class DatePicker extends React.Component { selectsMultiple, selectedDates, minTime, + swapRange, } = this.props; if ( @@ -690,7 +693,11 @@ export default class DatePicker extends React.Component { if (changedDate === null) { onChange([null, null], event); } else if (isDateBefore(changedDate, startDate)) { - onChange([changedDate, null], event); + if (swapRange) { + onChange([changedDate, startDate], event); + } else { + onChange([changedDate, null], event); + } } else { onChange([startDate, changedDate], event); } diff --git a/test/datepicker_test.test.js b/test/datepicker_test.test.js index bd2c7b372..bc51ebcb1 100644 --- a/test/datepicker_test.test.js +++ b/test/datepicker_test.test.js @@ -2217,6 +2217,42 @@ describe("DatePicker", () => { ); expect(endDate).toBeNull(); }); + + it("should swap dates of range when endDate set before startDate", () => { + const selected = utils.newDate("2024-04-03"); + const selectedPrevious = utils.subDays(selected, 3); + let [startDate, endDate] = [selected, null]; + const onChange = (dates = []) => { + [startDate, endDate] = dates; + }; + const { container } = render( + , + ); + + let selectedDay = findSelectedDay(container, selectedPrevious); + // Ensure that we're dealing with a date at the beginning of the month + if (!selectedDay) { + // If it's the beginning of the month & if the selectedPrevious is not being displayed, navigate to the previous month and reselect the selectedPrevious + goToLastMonth(container); + selectedDay = findSelectedDay(container, selectedPrevious); + } + + fireEvent.click(selectedDay); + expect(utils.formatDate(startDate, "yyyy-MM-dd")).toBe( + utils.formatDate(selectedPrevious, "yyyy-MM-dd"), + ); + expect(utils.formatDate(endDate, "yyyy-MM-dd")).toBe( + utils.formatDate(selected, "yyyy-MM-dd"), + ); + }); }); describe("selectsRange without inline", () => {