diff --git a/README.md b/README.md
index 590d0ba3d..27bc4ae3f 100644
--- a/README.md
+++ b/README.md
@@ -113,7 +113,8 @@ scroll | Object | { enabled: false }| infinite
showMonthArrow | Boolean | true | show/hide month arrow button
navigatorRenderer | Func | | renderer for focused date navigation area. fn(currentFocusedDate: Date, changeShownDate: func, props: object)
ranges | *Object[] | [] | Defines ranges. array of range object
-moveRangeOnFirstSelection(DateRange) | Boolean | false | move range on startDate selection. Otherwise endDate will replace with startDate.
+moveRangeOnFirstSelection(DateRange) | Boolean | false | move range on startDate selection. Otherwise endDate will replace with startDate unless `retainEndDateOnFirstSelection` is set to true.
+retainEndDateOnFirstSelection(DateRange) | Boolean | false | Retain end date when the start date is changed, unless start date is later than end date. Ignored if `moveRangeOnFirstSelection` is set to true.
onChange(Calendar) | Func | | callback function for date changes. fn(date: Date)
onChange(DateRange) | Func | | callback function for range changes. fn(changes). changes contains changed ranges with new `startDate`/`endDate` properties.
color(Calendar) | String | `#3d91ff` | defines color for selected date in Calendar
diff --git a/src/components/DateRange/README.md b/src/components/DateRange/README.md
index f26451ce5..73ad65a8b 100644
--- a/src/components/DateRange/README.md
+++ b/src/components/DateRange/README.md
@@ -3,9 +3,10 @@ This component extends all the props of **[Calendar](#calendar)** component. In
| Prop Name | Type |
|---|---|
| **moveRangeOnFirstSelection** | boolean |
-| **onRangeFocusChange** | function |
-| **rangeColors** | array |
-| **ranges** | array |
+| **retainEndDateOnFirstSelection** | boolean |
+| **onRangeFocusChange** | function |
+| **rangeColors** | array |
+| **ranges** | array |
#### Example: Editable Date Inputs
diff --git a/src/components/DateRange/index.js b/src/components/DateRange/index.js
index e2d968ead..3c963ecd2 100644
--- a/src/components/DateRange/index.js
+++ b/src/components/DateRange/index.js
@@ -18,22 +18,40 @@ class DateRange extends Component {
}
calcNewSelection = (value, isSingleValue = true) => {
const focusedRange = this.props.focusedRange || this.state.focusedRange;
- const { ranges, onChange, maxDate, moveRangeOnFirstSelection, disabledDates } = this.props;
+ const {
+ ranges,
+ onChange,
+ maxDate,
+ moveRangeOnFirstSelection,
+ retainEndDateOnFirstSelection,
+ disabledDates,
+ } = this.props;
const focusedRangeIndex = focusedRange[0];
const selectedRange = ranges[focusedRangeIndex];
if (!selectedRange || !onChange) return {};
-
let { startDate, endDate } = selectedRange;
- if (!endDate) endDate = new Date(startDate);
+ const now = new Date();
let nextFocusRange;
if (!isSingleValue) {
startDate = value.startDate;
endDate = value.endDate;
} else if (focusedRange[1] === 0) {
// startDate selection
- const dayOffset = differenceInCalendarDays(endDate, startDate);
+ const dayOffset = differenceInCalendarDays(endDate || now, startDate);
+ const calculateEndDate = () => {
+ if (moveRangeOnFirstSelection) {
+ return addDays(value, dayOffset);
+ }
+ if (retainEndDateOnFirstSelection) {
+ if (!endDate || isBefore(value, endDate)) {
+ return endDate;
+ }
+ return value;
+ }
+ return value || now;
+ };
startDate = value;
- endDate = moveRangeOnFirstSelection ? addDays(value, dayOffset) : value;
+ endDate = calculateEndDate();
if (maxDate) endDate = min([endDate, maxDate]);
nextFocusRange = [focusedRange[0], 1];
} else {
@@ -131,6 +149,7 @@ DateRange.defaultProps = {
classNames: {},
ranges: [],
moveRangeOnFirstSelection: false,
+ retainEndDateOnFirstSelection: false,
rangeColors: ['#3d91ff', '#3ecf8e', '#fed14c'],
disabledDates: [],
};
@@ -142,6 +161,7 @@ DateRange.propTypes = {
className: PropTypes.string,
ranges: PropTypes.arrayOf(rangeShape),
moveRangeOnFirstSelection: PropTypes.bool,
+ retainEndDateOnFirstSelection: PropTypes.bool,
};
export default DateRange;
diff --git a/src/components/DateRange/index.test.js b/src/components/DateRange/index.test.js
index e26aa6630..9c3fcdf1d 100644
--- a/src/components/DateRange/index.test.js
+++ b/src/components/DateRange/index.test.js
@@ -1,7 +1,84 @@
+import React from 'react';
+import { subDays, addDays, isSameDay } from 'date-fns';
import DateRange from '../DateRange';
+import renderer from 'react-test-renderer';
+
+let testRenderer = null;
+let instance = null;
+const endDate = new Date();
+const startDate = subDays(endDate, 7);
+
+const commonProps = {
+ ranges: [{ startDate, endDate, key: 'selection' }],
+ onChange: () => {},
+ moveRangeOnFirstSelection: false,
+};
+
+const compareRanges = (newRange, assertionRange) => {
+ ['startDate', 'endDate'].forEach(key => {
+ if (!newRange[key] || !assertionRange[key]) {
+ return expect(newRange[key]).toEqual(assertionRange[key]);
+ }
+ return expect(isSameDay(newRange[key], assertionRange[key])).toEqual(true);
+ });
+};
+
+beforeEach(() => {
+ testRenderer = renderer.create();
+ instance = testRenderer.getInstance();
+});
describe('DateRange', () => {
test('Should resolve', () => {
expect(DateRange).toEqual(expect.anything());
});
+
+ test('calculate new selection by resetting end date', () => {
+ const methodResult = instance.calcNewSelection(subDays(endDate, 10), true);
+ compareRanges(methodResult.range, {
+ startDate: subDays(endDate, 10),
+ endDate: subDays(endDate, 10),
+ });
+ });
+
+ test('calculate new selection by resetting end date if start date is not before', () => {
+ const methodResult = instance.calcNewSelection(addDays(endDate, 2), true);
+ compareRanges(methodResult.range, {
+ startDate: addDays(endDate, 2),
+ endDate: addDays(endDate, 2),
+ });
+ });
+
+ test('calculate new selection based on moveRangeOnFirstSelection prop', () => {
+ testRenderer.update();
+ const methodResult = instance.calcNewSelection(subDays(endDate, 10), true);
+ compareRanges(methodResult.range, {
+ startDate: subDays(endDate, 10),
+ endDate: subDays(endDate, 3),
+ });
+ });
+
+ test('calculate new selection by retaining end date, based on retainEndDateOnFirstSelection prop', () => {
+ testRenderer.update();
+ const methodResult = instance.calcNewSelection(subDays(endDate, 10), true);
+ compareRanges(methodResult.range, {
+ startDate: subDays(endDate, 10),
+ endDate,
+ });
+ });
+
+ test('calculate new selection by retaining the unset end date, based on retainEndDateOnFirstSelection prop', () => {
+ testRenderer.update(
+
+ );
+ const methodResult = instance.calcNewSelection(subDays(endDate, 10), true);
+ compareRanges(methodResult.range, {
+ startDate: subDays(endDate, 10),
+ endDate: null,
+ });
+ });
});