Skip to content
This repository was archived by the owner on May 19, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 4 additions & 3 deletions src/components/DateRange/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
30 changes: 25 additions & 5 deletions src/components/DateRange/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -131,6 +149,7 @@ DateRange.defaultProps = {
classNames: {},
ranges: [],
moveRangeOnFirstSelection: false,
retainEndDateOnFirstSelection: false,
rangeColors: ['#3d91ff', '#3ecf8e', '#fed14c'],
disabledDates: [],
};
Expand All @@ -142,6 +161,7 @@ DateRange.propTypes = {
className: PropTypes.string,
ranges: PropTypes.arrayOf(rangeShape),
moveRangeOnFirstSelection: PropTypes.bool,
retainEndDateOnFirstSelection: PropTypes.bool,
};

export default DateRange;
77 changes: 77 additions & 0 deletions src/components/DateRange/index.test.js
Original file line number Diff line number Diff line change
@@ -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(<DateRange {...commonProps} />);
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(<DateRange {...commonProps} moveRangeOnFirstSelection />);
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(<DateRange {...commonProps} retainEndDateOnFirstSelection />);
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(
<DateRange
{...commonProps}
ranges={[{ ...commonProps.ranges[0], endDate: null }]}
retainEndDateOnFirstSelection
/>
);
const methodResult = instance.calcNewSelection(subDays(endDate, 10), true);
compareRanges(methodResult.range, {
startDate: subDays(endDate, 10),
endDate: null,
});
});
});