-
Notifications
You must be signed in to change notification settings - Fork 2.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support selecting multiple dates #3999
Changes from 5 commits
b2cca19
a776678
5052d88
52603c2
0df17aa
40b5f05
a5225ec
7092c09
9593bcb
f6e2d80
3151397
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
() => { | ||
const [selectedDates, setSelectedDates] = useState([new Date()]); | ||
const onChange = (dates) => { | ||
setSelectedDates(dates); | ||
}; | ||
return ( | ||
<DatePicker | ||
selectedDates={selectedDates} | ||
selectsMultiple | ||
onChange={onChange} | ||
shouldCloseOnSelect={false} | ||
disabledKeyboardNavigation | ||
/> | ||
); | ||
}; |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -185,6 +185,23 @@ | |||||
return `${formattedStartDate} - ${formattedEndDate}`; | ||||||
} | ||||||
|
||||||
export function safeMultipleDatesFormat(dates, props) { | ||||||
if (!dates || !dates.length) { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
return ""; | ||||||
} | ||||||
const formattedFirstDate = safeDateFormat(dates[0], props); | ||||||
if (dates.length === 1) { | ||||||
return formattedFirstDate; | ||||||
} | ||||||
if (dates.length === 2) { | ||||||
const formattedSecondDate = safeDateFormat(dates[1], props); | ||||||
return `${formattedFirstDate}, ${formattedSecondDate}`; | ||||||
} | ||||||
|
||||||
const extraDatesCount = dates.length - 1; | ||||||
return `${formattedFirstDate} (+${extraDatesCount})`; | ||||||
} | ||||||
|
||||||
// ** Date Setters ** | ||||||
|
||||||
export function setTime(date, { hour = 0, minute = 0, second = 0 }) { | ||||||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -42,6 +42,8 @@ | |||||||||||||||||||||||||||||||||||
showWeekPicker: PropTypes.bool, | ||||||||||||||||||||||||||||||||||||
showWeekNumber: PropTypes.bool, | ||||||||||||||||||||||||||||||||||||
selectsDisabledDaysInRange: PropTypes.bool, | ||||||||||||||||||||||||||||||||||||
selectsMultiple: PropTypes.bool, | ||||||||||||||||||||||||||||||||||||
selectedDates: PropTypes.arrayOf(PropTypes.instanceOf(Date)), | ||||||||||||||||||||||||||||||||||||
startDate: PropTypes.instanceOf(Date), | ||||||||||||||||||||||||||||||||||||
renderDayContents: PropTypes.func, | ||||||||||||||||||||||||||||||||||||
handleOnKeyDown: PropTypes.func, | ||||||||||||||||||||||||||||||||||||
|
@@ -93,14 +95,25 @@ | |||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
isSameDay = (other) => isSameDay(this.props.day, other); | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
isKeyboardSelected = () => | ||||||||||||||||||||||||||||||||||||
!this.props.disabledKeyboardNavigation && | ||||||||||||||||||||||||||||||||||||
!( | ||||||||||||||||||||||||||||||||||||
this.isSameDay(this.props.selected) || | ||||||||||||||||||||||||||||||||||||
this.isSameWeek(this.props.selected) | ||||||||||||||||||||||||||||||||||||
) && | ||||||||||||||||||||||||||||||||||||
(this.isSameDay(this.props.preSelection) || | ||||||||||||||||||||||||||||||||||||
this.isSameWeek(this.props.preSelection)); | ||||||||||||||||||||||||||||||||||||
isKeyboardSelected = () => { | ||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||||||||||||||||||||||||||||||||
if (this.props.disabledKeyboardNavigation) { | ||||||||||||||||||||||||||||||||||||
return false; | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
if (this.props.selectsMultiple) { | ||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hi @nandorojo 👋 |
||||||||||||||||||||||||||||||||||||
const isSelectedDate = (this.props.selectedDates || []).some((date) => | ||||||||||||||||||||||||||||||||||||
this.isSameDay(date) | ||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||
return !isSelectedDate && this.isSameDay(this.props.preSelection); | ||||||||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||||||||
return !( | ||||||||||||||||||||||||||||||||||||
this.isSameDay(this.props.selected) || | ||||||||||||||||||||||||||||||||||||
this.isSameWeek(this.props.selected) | ||||||||||||||||||||||||||||||||||||
) && ( | ||||||||||||||||||||||||||||||||||||
this.isSameDay(this.props.preSelection) || | ||||||||||||||||||||||||||||||||||||
this.isSameWeek(this.props.preSelection) | ||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
Comment on lines
+107
to
+115
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the else clause should not be necessary, as the if above ends with a return, so we can skip an indentation here
Suggested change
|
||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
isDisabled = () => isDayDisabled(this.props.day, this.props); | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
|
@@ -275,9 +288,13 @@ | |||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
isCurrentDay = () => this.isSameDay(newDate()); | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
isSelected = () => | ||||||||||||||||||||||||||||||||||||
this.isSameDay(this.props.selected) || this.isSameWeek(this.props.selected); | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
isSelected = () => { | ||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||||||||||||||||||||||||||||||||
if (this.props.selectsMultiple && this.props.selectedDates) { | ||||||||||||||||||||||||||||||||||||
return this.props.selectedDates.some((date) => this.isSameDay(date)); | ||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||
return this.isSameDay(this.props.selected) || this.isSameWeek(this.props.selected); | ||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||
Comment on lines
+292
to
+297
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This looks sketchy, as it will fall through to checking on props.selected, if this.props.selectsMultiple is true, and this.props.selectedDates is undefined. Perhaps something in the line of this instead (I added test on
Suggested change
|
||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
getClassNames = (date) => { | ||||||||||||||||||||||||||||||||||||
const dayClassName = this.props.dayClassName | ||||||||||||||||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -45,6 +45,7 @@ | |||||||||
isSameDay, | ||||||||||
isMonthDisabled, | ||||||||||
isYearDisabled, | ||||||||||
safeMultipleDatesFormat, | ||||||||||
getHolidaysMap, | ||||||||||
isDateBefore, | ||||||||||
} from "./date_utils"; | ||||||||||
|
@@ -230,6 +231,8 @@ | |||||||||
selectsStart: PropTypes.bool, | ||||||||||
selectsRange: PropTypes.bool, | ||||||||||
selectsDisabledDaysInRange: PropTypes.bool, | ||||||||||
selectsMultiple: PropTypes.bool, | ||||||||||
selectedDates: PropTypes.arrayOf(PropTypes.instanceOf(Date)), | ||||||||||
showMonthDropdown: PropTypes.bool, | ||||||||||
showPreviousMonths: PropTypes.bool, | ||||||||||
showMonthYearDropdown: PropTypes.bool, | ||||||||||
|
@@ -621,12 +624,20 @@ | |||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
const { onChange, selectsRange, startDate, endDate } = this.props; | ||||||||||
const { | ||||||||||
onChange, | ||||||||||
selectsRange, | ||||||||||
startDate, | ||||||||||
endDate, | ||||||||||
selectsMultiple, | ||||||||||
selectedDates, | ||||||||||
} = this.props; | ||||||||||
|
||||||||||
if ( | ||||||||||
!isEqual(this.props.selected, changedDate) || | ||||||||||
this.props.allowSameDay || | ||||||||||
selectsRange | ||||||||||
selectsRange || | ||||||||||
selectsMultiple | ||||||||||
) { | ||||||||||
if (changedDate !== null) { | ||||||||||
if ( | ||||||||||
|
@@ -667,6 +678,26 @@ | |||||||||
if (isRangeFilled) { | ||||||||||
onChange([changedDate, null], event); | ||||||||||
} | ||||||||||
} else if (selectsMultiple) { | ||||||||||
const noSelectedDates = !selectedDates || selectedDates.length === 0; | ||||||||||
|
||||||||||
if (noSelectedDates) { | ||||||||||
Comment on lines
+682
to
+684
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tend to prefer these type of checks here
Suggested change
|
||||||||||
onChange([changedDate], event); | ||||||||||
} else { | ||||||||||
const isChangedDateAlreadySelected = selectedDates.some( | ||||||||||
(selectedDate) => isSameDay(selectedDate, changedDate) | ||||||||||
); | ||||||||||
|
||||||||||
if (isChangedDateAlreadySelected) { | ||||||||||
const nextDates = selectedDates.filter( | ||||||||||
(selectedDate) => !isSameDay(selectedDate, changedDate) | ||||||||||
); | ||||||||||
|
||||||||||
onChange(nextDates, event); | ||||||||||
} else { | ||||||||||
onChange([...selectedDates, changedDate], event); | ||||||||||
} | ||||||||||
} | ||||||||||
} else { | ||||||||||
onChange(changedDate, event); | ||||||||||
} | ||||||||||
|
@@ -1011,6 +1042,8 @@ | |||||||||
selectsStart={this.props.selectsStart} | ||||||||||
selectsEnd={this.props.selectsEnd} | ||||||||||
selectsRange={this.props.selectsRange} | ||||||||||
selectsMultiple={this.props.selectsMultiple} | ||||||||||
selectedDates={this.props.selectedDates} | ||||||||||
startDate={this.props.startDate} | ||||||||||
endDate={this.props.endDate} | ||||||||||
excludeDates={this.props.excludeDates} | ||||||||||
|
@@ -1194,6 +1227,8 @@ | |||||||||
this.props.endDate, | ||||||||||
this.props, | ||||||||||
) | ||||||||||
: this.props.selectsMultiple | ||||||||||
? safeMultipleDatesFormat(this.props.selectedDates, this.props) | ||||||||||
: safeDateFormat(this.props.selected, this.props); | ||||||||||
|
||||||||||
return React.cloneElement(customInput, { | ||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should the example show where to import this from?
🔸 Reduce Future Bugs (Important)
Graham C
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The examples added here are automatically published to https://reactdatepicker.com/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, but how does someone who what line to write in the code to get to the
DatePicker
component. I am suggesting we add an import line at the top of this example. I guess this is an existing problem with all the examples, so probably out of scope to change.Graham C
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Normally I would, but I just copied what the other examples did.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps we can start by leading with example here and add the import to show how to get it done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good to me.
Graham C
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That will fix the automation complaining about DatePicker not being defined...
Andy W