1 | import React from 'react';
|
2 | import PropTypes from 'prop-types';
|
3 | import momentPropTypes from 'react-moment-proptypes';
|
4 | import { forbidExtraProps, mutuallyExclusiveProps, nonNegativeInteger } from 'airbnb-prop-types';
|
5 | import moment from 'moment';
|
6 | import values from 'object.values';
|
7 | import isTouchDevice from 'is-touch-device';
|
8 |
|
9 | import { DayPickerPhrases } from '../defaultPhrases';
|
10 | import getPhrasePropTypes from '../utils/getPhrasePropTypes';
|
11 |
|
12 | import isInclusivelyAfterDay from '../utils/isInclusivelyAfterDay';
|
13 | import isNextDay from '../utils/isNextDay';
|
14 | import isSameDay from '../utils/isSameDay';
|
15 | import isAfterDay from '../utils/isAfterDay';
|
16 | import isBeforeDay from '../utils/isBeforeDay';
|
17 |
|
18 | import getVisibleDays from '../utils/getVisibleDays';
|
19 | import isDayVisible from '../utils/isDayVisible';
|
20 |
|
21 | import getSelectedDateOffset from '../utils/getSelectedDateOffset';
|
22 |
|
23 | import toISODateString from '../utils/toISODateString';
|
24 | import { addModifier, deleteModifier } from '../utils/modifiers';
|
25 |
|
26 | import DisabledShape from '../shapes/DisabledShape';
|
27 | import FocusedInputShape from '../shapes/FocusedInputShape';
|
28 | import ScrollableOrientationShape from '../shapes/ScrollableOrientationShape';
|
29 | import DayOfWeekShape from '../shapes/DayOfWeekShape';
|
30 | import CalendarInfoPositionShape from '../shapes/CalendarInfoPositionShape';
|
31 |
|
32 | import {
|
33 | START_DATE,
|
34 | END_DATE,
|
35 | HORIZONTAL_ORIENTATION,
|
36 | VERTICAL_SCROLLABLE,
|
37 | DAY_SIZE,
|
38 | INFO_POSITION_BOTTOM,
|
39 | } from '../constants';
|
40 |
|
41 | import DayPicker from './DayPicker';
|
42 | import getPooledMoment from '../utils/getPooledMoment';
|
43 |
|
44 | const propTypes = forbidExtraProps({
|
45 | startDate: momentPropTypes.momentObj,
|
46 | endDate: momentPropTypes.momentObj,
|
47 | onDatesChange: PropTypes.func,
|
48 | startDateOffset: PropTypes.func,
|
49 | endDateOffset: PropTypes.func,
|
50 | minDate: momentPropTypes.momentObj,
|
51 | maxDate: momentPropTypes.momentObj,
|
52 |
|
53 | focusedInput: FocusedInputShape,
|
54 | onFocusChange: PropTypes.func,
|
55 | onClose: PropTypes.func,
|
56 |
|
57 | keepOpenOnDateSelect: PropTypes.bool,
|
58 | minimumNights: PropTypes.number,
|
59 | disabled: DisabledShape,
|
60 | isOutsideRange: PropTypes.func,
|
61 | isDayBlocked: PropTypes.func,
|
62 | isDayHighlighted: PropTypes.func,
|
63 | getMinNightsForHoverDate: PropTypes.func,
|
64 |
|
65 |
|
66 | renderMonthText: mutuallyExclusiveProps(PropTypes.func, 'renderMonthText', 'renderMonthElement'),
|
67 | renderMonthElement: mutuallyExclusiveProps(PropTypes.func, 'renderMonthText', 'renderMonthElement'),
|
68 | renderWeekHeaderElement: PropTypes.func,
|
69 | enableOutsideDays: PropTypes.bool,
|
70 | numberOfMonths: PropTypes.number,
|
71 | orientation: ScrollableOrientationShape,
|
72 | withPortal: PropTypes.bool,
|
73 | initialVisibleMonth: PropTypes.func,
|
74 | hideKeyboardShortcutsPanel: PropTypes.bool,
|
75 | daySize: nonNegativeInteger,
|
76 | noBorder: PropTypes.bool,
|
77 | verticalBorderSpacing: nonNegativeInteger,
|
78 | horizontalMonthPadding: nonNegativeInteger,
|
79 |
|
80 | navPrev: PropTypes.node,
|
81 | navNext: PropTypes.node,
|
82 | noNavButtons: PropTypes.bool,
|
83 |
|
84 | onPrevMonthClick: PropTypes.func,
|
85 | onNextMonthClick: PropTypes.func,
|
86 | onOutsideClick: PropTypes.func,
|
87 | renderCalendarDay: PropTypes.func,
|
88 | renderDayContents: PropTypes.func,
|
89 | renderCalendarInfo: PropTypes.func,
|
90 | renderKeyboardShortcutsButton: PropTypes.func,
|
91 | calendarInfoPosition: CalendarInfoPositionShape,
|
92 | firstDayOfWeek: DayOfWeekShape,
|
93 | verticalHeight: nonNegativeInteger,
|
94 | transitionDuration: nonNegativeInteger,
|
95 |
|
96 |
|
97 | onBlur: PropTypes.func,
|
98 | isFocused: PropTypes.bool,
|
99 | showKeyboardShortcuts: PropTypes.bool,
|
100 | onTab: PropTypes.func,
|
101 | onShiftTab: PropTypes.func,
|
102 |
|
103 |
|
104 | monthFormat: PropTypes.string,
|
105 | weekDayFormat: PropTypes.string,
|
106 | phrases: PropTypes.shape(getPhrasePropTypes(DayPickerPhrases)),
|
107 | dayAriaLabelFormat: PropTypes.string,
|
108 |
|
109 | isRTL: PropTypes.bool,
|
110 | });
|
111 |
|
112 | const defaultProps = {
|
113 | startDate: undefined,
|
114 | endDate: undefined,
|
115 | minDate: null,
|
116 | maxDate: null,
|
117 | onDatesChange() {},
|
118 | startDateOffset: undefined,
|
119 | endDateOffset: undefined,
|
120 |
|
121 | focusedInput: null,
|
122 | onFocusChange() {},
|
123 | onClose() {},
|
124 |
|
125 | keepOpenOnDateSelect: false,
|
126 | minimumNights: 1,
|
127 | disabled: false,
|
128 | isOutsideRange() {},
|
129 | isDayBlocked() {},
|
130 | isDayHighlighted() {},
|
131 | getMinNightsForHoverDate() {},
|
132 |
|
133 |
|
134 | renderMonthText: null,
|
135 | renderWeekHeaderElement: null,
|
136 | enableOutsideDays: false,
|
137 | numberOfMonths: 1,
|
138 | orientation: HORIZONTAL_ORIENTATION,
|
139 | withPortal: false,
|
140 | hideKeyboardShortcutsPanel: false,
|
141 | initialVisibleMonth: null,
|
142 | daySize: DAY_SIZE,
|
143 |
|
144 | navPrev: null,
|
145 | navNext: null,
|
146 | noNavButtons: false,
|
147 |
|
148 | onPrevMonthClick() {},
|
149 | onNextMonthClick() {},
|
150 | onOutsideClick() {},
|
151 |
|
152 | renderCalendarDay: undefined,
|
153 | renderDayContents: null,
|
154 | renderCalendarInfo: null,
|
155 | renderMonthElement: null,
|
156 | renderKeyboardShortcutsButton: undefined,
|
157 | calendarInfoPosition: INFO_POSITION_BOTTOM,
|
158 | firstDayOfWeek: null,
|
159 | verticalHeight: null,
|
160 | noBorder: false,
|
161 | transitionDuration: undefined,
|
162 | verticalBorderSpacing: undefined,
|
163 | horizontalMonthPadding: 13,
|
164 |
|
165 |
|
166 | onBlur() {},
|
167 | isFocused: false,
|
168 | showKeyboardShortcuts: false,
|
169 | onTab() {},
|
170 | onShiftTab() {},
|
171 |
|
172 |
|
173 | monthFormat: 'MMMM YYYY',
|
174 | weekDayFormat: 'dd',
|
175 | phrases: DayPickerPhrases,
|
176 | dayAriaLabelFormat: undefined,
|
177 |
|
178 | isRTL: false,
|
179 | };
|
180 |
|
181 | const getChooseAvailableDatePhrase = (phrases, focusedInput) => {
|
182 | if (focusedInput === START_DATE) {
|
183 | return phrases.chooseAvailableStartDate;
|
184 | }
|
185 | if (focusedInput === END_DATE) {
|
186 | return phrases.chooseAvailableEndDate;
|
187 | }
|
188 | return phrases.chooseAvailableDate;
|
189 | };
|
190 |
|
191 | export default class DayPickerRangeController extends React.PureComponent {
|
192 | constructor(props) {
|
193 | super(props);
|
194 |
|
195 | this.isTouchDevice = isTouchDevice();
|
196 | this.today = moment();
|
197 | this.modifiers = {
|
198 | today: (day) => this.isToday(day),
|
199 | blocked: (day) => this.isBlocked(day),
|
200 | 'blocked-calendar': (day) => props.isDayBlocked(day),
|
201 | 'blocked-out-of-range': (day) => props.isOutsideRange(day),
|
202 | 'highlighted-calendar': (day) => props.isDayHighlighted(day),
|
203 | valid: (day) => !this.isBlocked(day),
|
204 | 'selected-start': (day) => this.isStartDate(day),
|
205 | 'selected-end': (day) => this.isEndDate(day),
|
206 | 'blocked-minimum-nights': (day) => this.doesNotMeetMinimumNights(day),
|
207 | 'selected-span': (day) => this.isInSelectedSpan(day),
|
208 | 'last-in-range': (day) => this.isLastInRange(day),
|
209 | hovered: (day) => this.isHovered(day),
|
210 | 'hovered-span': (day) => this.isInHoveredSpan(day),
|
211 | 'hovered-offset': (day) => this.isInHoveredSpan(day),
|
212 | 'after-hovered-start': (day) => this.isDayAfterHoveredStartDate(day),
|
213 | 'first-day-of-week': (day) => this.isFirstDayOfWeek(day),
|
214 | 'last-day-of-week': (day) => this.isLastDayOfWeek(day),
|
215 | 'hovered-start-first-possible-end': (day, hoverDate) => this.isFirstPossibleEndDateForHoveredStartDate(day, hoverDate),
|
216 | 'hovered-start-blocked-minimum-nights': (day, hoverDate) => this.doesNotMeetMinNightsForHoveredStartDate(day, hoverDate),
|
217 | };
|
218 |
|
219 | const { currentMonth, visibleDays } = this.getStateForNewMonth(props);
|
220 |
|
221 |
|
222 |
|
223 | const chooseAvailableDate = getChooseAvailableDatePhrase(props.phrases, props.focusedInput);
|
224 |
|
225 | this.state = {
|
226 | hoverDate: null,
|
227 | currentMonth,
|
228 | phrases: {
|
229 | ...props.phrases,
|
230 | chooseAvailableDate,
|
231 | },
|
232 | visibleDays,
|
233 | disablePrev: this.shouldDisableMonthNavigation(props.minDate, currentMonth),
|
234 | disableNext: this.shouldDisableMonthNavigation(props.maxDate, currentMonth),
|
235 | };
|
236 |
|
237 | this.onDayClick = this.onDayClick.bind(this);
|
238 | this.onDayMouseEnter = this.onDayMouseEnter.bind(this);
|
239 | this.onDayMouseLeave = this.onDayMouseLeave.bind(this);
|
240 | this.onPrevMonthClick = this.onPrevMonthClick.bind(this);
|
241 | this.onNextMonthClick = this.onNextMonthClick.bind(this);
|
242 | this.onMonthChange = this.onMonthChange.bind(this);
|
243 | this.onYearChange = this.onYearChange.bind(this);
|
244 | this.onMultiplyScrollableMonths = this.onMultiplyScrollableMonths.bind(this);
|
245 | this.getFirstFocusableDay = this.getFirstFocusableDay.bind(this);
|
246 | }
|
247 |
|
248 | componentWillReceiveProps(nextProps) {
|
249 | const {
|
250 | startDate,
|
251 | endDate,
|
252 | focusedInput,
|
253 | getMinNightsForHoverDate,
|
254 | minimumNights,
|
255 | isOutsideRange,
|
256 | isDayBlocked,
|
257 | isDayHighlighted,
|
258 | phrases,
|
259 | initialVisibleMonth,
|
260 | numberOfMonths,
|
261 | enableOutsideDays,
|
262 | } = nextProps;
|
263 |
|
264 | const {
|
265 | startDate: prevStartDate,
|
266 | endDate: prevEndDate,
|
267 | focusedInput: prevFocusedInput,
|
268 | minimumNights: prevMinimumNights,
|
269 | isOutsideRange: prevIsOutsideRange,
|
270 | isDayBlocked: prevIsDayBlocked,
|
271 | isDayHighlighted: prevIsDayHighlighted,
|
272 | phrases: prevPhrases,
|
273 | initialVisibleMonth: prevInitialVisibleMonth,
|
274 | numberOfMonths: prevNumberOfMonths,
|
275 | enableOutsideDays: prevEnableOutsideDays,
|
276 | } = this.props;
|
277 |
|
278 | const { hoverDate } = this.state;
|
279 | let { visibleDays } = this.state;
|
280 |
|
281 | let recomputeOutsideRange = false;
|
282 | let recomputeDayBlocked = false;
|
283 | let recomputeDayHighlighted = false;
|
284 |
|
285 | if (isOutsideRange !== prevIsOutsideRange) {
|
286 | this.modifiers['blocked-out-of-range'] = (day) => isOutsideRange(day);
|
287 | recomputeOutsideRange = true;
|
288 | }
|
289 |
|
290 | if (isDayBlocked !== prevIsDayBlocked) {
|
291 | this.modifiers['blocked-calendar'] = (day) => isDayBlocked(day);
|
292 | recomputeDayBlocked = true;
|
293 | }
|
294 |
|
295 | if (isDayHighlighted !== prevIsDayHighlighted) {
|
296 | this.modifiers['highlighted-calendar'] = (day) => isDayHighlighted(day);
|
297 | recomputeDayHighlighted = true;
|
298 | }
|
299 |
|
300 | const recomputePropModifiers = (
|
301 | recomputeOutsideRange || recomputeDayBlocked || recomputeDayHighlighted
|
302 | );
|
303 |
|
304 | const didStartDateChange = startDate !== prevStartDate;
|
305 | const didEndDateChange = endDate !== prevEndDate;
|
306 | const didFocusChange = focusedInput !== prevFocusedInput;
|
307 |
|
308 | if (
|
309 | numberOfMonths !== prevNumberOfMonths
|
310 | || enableOutsideDays !== prevEnableOutsideDays
|
311 | || (
|
312 | initialVisibleMonth !== prevInitialVisibleMonth
|
313 | && !prevFocusedInput
|
314 | && didFocusChange
|
315 | )
|
316 | ) {
|
317 | const newMonthState = this.getStateForNewMonth(nextProps);
|
318 | const { currentMonth } = newMonthState;
|
319 | ({ visibleDays } = newMonthState);
|
320 | this.setState({
|
321 | currentMonth,
|
322 | visibleDays,
|
323 | });
|
324 | }
|
325 |
|
326 | let modifiers = {};
|
327 |
|
328 | if (didStartDateChange) {
|
329 | modifiers = this.deleteModifier(modifiers, prevStartDate, 'selected-start');
|
330 | modifiers = this.addModifier(modifiers, startDate, 'selected-start');
|
331 |
|
332 | if (prevStartDate) {
|
333 | const startSpan = prevStartDate.clone().add(1, 'day');
|
334 | const endSpan = prevStartDate.clone().add(prevMinimumNights + 1, 'days');
|
335 | modifiers = this.deleteModifierFromRange(modifiers, startSpan, endSpan, 'after-hovered-start');
|
336 | }
|
337 | }
|
338 |
|
339 | if (didEndDateChange) {
|
340 | modifiers = this.deleteModifier(modifiers, prevEndDate, 'selected-end');
|
341 | modifiers = this.addModifier(modifiers, endDate, 'selected-end');
|
342 | }
|
343 |
|
344 | if (didStartDateChange || didEndDateChange) {
|
345 | if (prevStartDate && prevEndDate) {
|
346 | modifiers = this.deleteModifierFromRange(
|
347 | modifiers,
|
348 | prevStartDate,
|
349 | prevEndDate.clone().add(1, 'day'),
|
350 | 'selected-span',
|
351 | );
|
352 | }
|
353 |
|
354 | if (startDate && endDate) {
|
355 | modifiers = this.deleteModifierFromRange(
|
356 | modifiers,
|
357 | startDate,
|
358 | endDate.clone().add(1, 'day'),
|
359 | 'hovered-span',
|
360 | );
|
361 |
|
362 | modifiers = this.addModifierToRange(
|
363 | modifiers,
|
364 | startDate.clone().add(1, 'day'),
|
365 | endDate,
|
366 | 'selected-span',
|
367 | );
|
368 | }
|
369 | }
|
370 |
|
371 | if (!this.isTouchDevice && didStartDateChange && startDate && !endDate) {
|
372 | const startSpan = startDate.clone().add(1, 'day');
|
373 | const endSpan = startDate.clone().add(minimumNights + 1, 'days');
|
374 | modifiers = this.addModifierToRange(modifiers, startSpan, endSpan, 'after-hovered-start');
|
375 | }
|
376 |
|
377 | if (prevMinimumNights > 0) {
|
378 | if (didFocusChange || didStartDateChange || minimumNights !== prevMinimumNights) {
|
379 | const startSpan = prevStartDate || this.today;
|
380 | modifiers = this.deleteModifierFromRange(
|
381 | modifiers,
|
382 | startSpan,
|
383 | startSpan.clone().add(prevMinimumNights, 'days'),
|
384 | 'blocked-minimum-nights',
|
385 | );
|
386 |
|
387 | modifiers = this.deleteModifierFromRange(
|
388 | modifiers,
|
389 | startSpan,
|
390 | startSpan.clone().add(prevMinimumNights, 'days'),
|
391 | 'blocked',
|
392 | );
|
393 | }
|
394 | }
|
395 |
|
396 | if (didFocusChange || recomputePropModifiers) {
|
397 | values(visibleDays).forEach((days) => {
|
398 | Object.keys(days).forEach((day) => {
|
399 | const momentObj = getPooledMoment(day);
|
400 | let isBlocked = false;
|
401 |
|
402 | if (didFocusChange || recomputeOutsideRange) {
|
403 | if (isOutsideRange(momentObj)) {
|
404 | modifiers = this.addModifier(modifiers, momentObj, 'blocked-out-of-range');
|
405 | isBlocked = true;
|
406 | } else {
|
407 | modifiers = this.deleteModifier(modifiers, momentObj, 'blocked-out-of-range');
|
408 | }
|
409 | }
|
410 |
|
411 | if (didFocusChange || recomputeDayBlocked) {
|
412 | if (isDayBlocked(momentObj)) {
|
413 | modifiers = this.addModifier(modifiers, momentObj, 'blocked-calendar');
|
414 | isBlocked = true;
|
415 | } else {
|
416 | modifiers = this.deleteModifier(modifiers, momentObj, 'blocked-calendar');
|
417 | }
|
418 | }
|
419 |
|
420 | if (isBlocked) {
|
421 | modifiers = this.addModifier(modifiers, momentObj, 'blocked');
|
422 | } else {
|
423 | modifiers = this.deleteModifier(modifiers, momentObj, 'blocked');
|
424 | }
|
425 |
|
426 | if (didFocusChange || recomputeDayHighlighted) {
|
427 | if (isDayHighlighted(momentObj)) {
|
428 | modifiers = this.addModifier(modifiers, momentObj, 'highlighted-calendar');
|
429 | } else {
|
430 | modifiers = this.deleteModifier(modifiers, momentObj, 'highlighted-calendar');
|
431 | }
|
432 | }
|
433 | });
|
434 | });
|
435 | }
|
436 |
|
437 | if (!this.isTouchDevice && didFocusChange && hoverDate && !this.isBlocked(hoverDate)) {
|
438 | const minNightsForHoverDate = getMinNightsForHoverDate(hoverDate);
|
439 | if (minNightsForHoverDate > 0 && focusedInput === END_DATE) {
|
440 | modifiers = this.deleteModifierFromRange(
|
441 | modifiers,
|
442 | hoverDate.clone().add(1, 'days'),
|
443 | hoverDate.clone().add(minNightsForHoverDate, 'days'),
|
444 | 'hovered-start-blocked-minimum-nights',
|
445 | );
|
446 |
|
447 | modifiers = this.deleteModifier(
|
448 | modifiers,
|
449 | hoverDate.clone().add(minNightsForHoverDate, 'days'),
|
450 | 'hovered-start-first-possible-end',
|
451 | );
|
452 | }
|
453 |
|
454 | if (minNightsForHoverDate > 0 && focusedInput === START_DATE) {
|
455 | modifiers = this.addModifierToRange(
|
456 | modifiers,
|
457 | hoverDate.clone().add(1, 'days'),
|
458 | hoverDate.clone().add(minNightsForHoverDate, 'days'),
|
459 | 'hovered-start-blocked-minimum-nights',
|
460 | );
|
461 |
|
462 | modifiers = this.addModifier(
|
463 | modifiers,
|
464 | hoverDate.clone().add(minNightsForHoverDate, 'days'),
|
465 | 'hovered-start-first-possible-end',
|
466 | );
|
467 | }
|
468 | }
|
469 |
|
470 | if (minimumNights > 0 && startDate && focusedInput === END_DATE) {
|
471 | modifiers = this.addModifierToRange(
|
472 | modifiers,
|
473 | startDate,
|
474 | startDate.clone().add(minimumNights, 'days'),
|
475 | 'blocked-minimum-nights',
|
476 | );
|
477 |
|
478 | modifiers = this.addModifierToRange(
|
479 | modifiers,
|
480 | startDate,
|
481 | startDate.clone().add(minimumNights, 'days'),
|
482 | 'blocked',
|
483 | );
|
484 | }
|
485 |
|
486 | const today = moment();
|
487 | if (!isSameDay(this.today, today)) {
|
488 | modifiers = this.deleteModifier(modifiers, this.today, 'today');
|
489 | modifiers = this.addModifier(modifiers, today, 'today');
|
490 | this.today = today;
|
491 | }
|
492 |
|
493 | if (Object.keys(modifiers).length > 0) {
|
494 | this.setState({
|
495 | visibleDays: {
|
496 | ...visibleDays,
|
497 | ...modifiers,
|
498 | },
|
499 | });
|
500 | }
|
501 |
|
502 | if (didFocusChange || phrases !== prevPhrases) {
|
503 |
|
504 | const chooseAvailableDate = getChooseAvailableDatePhrase(phrases, focusedInput);
|
505 |
|
506 | this.setState({
|
507 | phrases: {
|
508 | ...phrases,
|
509 | chooseAvailableDate,
|
510 | },
|
511 | });
|
512 | }
|
513 | }
|
514 |
|
515 | onDayClick(day, e) {
|
516 | const {
|
517 | keepOpenOnDateSelect,
|
518 | minimumNights,
|
519 | onBlur,
|
520 | focusedInput,
|
521 | onFocusChange,
|
522 | onClose,
|
523 | onDatesChange,
|
524 | startDateOffset,
|
525 | endDateOffset,
|
526 | disabled,
|
527 | } = this.props;
|
528 |
|
529 | if (e) e.preventDefault();
|
530 | if (this.isBlocked(day)) return;
|
531 |
|
532 | let { startDate, endDate } = this.props;
|
533 |
|
534 | if (startDateOffset || endDateOffset) {
|
535 | startDate = getSelectedDateOffset(startDateOffset, day);
|
536 | endDate = getSelectedDateOffset(endDateOffset, day);
|
537 |
|
538 | if (this.isBlocked(startDate) || this.isBlocked(endDate)) {
|
539 | return;
|
540 | }
|
541 |
|
542 | onDatesChange({ startDate, endDate });
|
543 |
|
544 | if (!keepOpenOnDateSelect) {
|
545 | onFocusChange(null);
|
546 | onClose({ startDate, endDate });
|
547 | }
|
548 | } else if (focusedInput === START_DATE) {
|
549 | const lastAllowedStartDate = endDate && endDate.clone().subtract(minimumNights, 'days');
|
550 | const isStartDateAfterEndDate = isBeforeDay(lastAllowedStartDate, day)
|
551 | || isAfterDay(startDate, endDate);
|
552 | const isEndDateDisabled = disabled === END_DATE;
|
553 |
|
554 | if (!isEndDateDisabled || !isStartDateAfterEndDate) {
|
555 | startDate = day;
|
556 | if (isStartDateAfterEndDate) {
|
557 | endDate = null;
|
558 | }
|
559 | }
|
560 |
|
561 | onDatesChange({ startDate, endDate });
|
562 |
|
563 | if (isEndDateDisabled && !isStartDateAfterEndDate) {
|
564 | onFocusChange(null);
|
565 | onClose({ startDate, endDate });
|
566 | } else if (!isEndDateDisabled) {
|
567 | onFocusChange(END_DATE);
|
568 | }
|
569 | } else if (focusedInput === END_DATE) {
|
570 | const firstAllowedEndDate = startDate && startDate.clone().add(minimumNights, 'days');
|
571 |
|
572 | if (!startDate) {
|
573 | endDate = day;
|
574 | onDatesChange({ startDate, endDate });
|
575 | onFocusChange(START_DATE);
|
576 | } else if (isInclusivelyAfterDay(day, firstAllowedEndDate)) {
|
577 | endDate = day;
|
578 | onDatesChange({ startDate, endDate });
|
579 | if (!keepOpenOnDateSelect) {
|
580 | onFocusChange(null);
|
581 | onClose({ startDate, endDate });
|
582 | }
|
583 | } else if (disabled !== START_DATE) {
|
584 | startDate = day;
|
585 | endDate = null;
|
586 | onDatesChange({ startDate, endDate });
|
587 | } else {
|
588 | onDatesChange({ startDate, endDate });
|
589 | }
|
590 | } else {
|
591 | onDatesChange({ startDate, endDate });
|
592 | }
|
593 |
|
594 | onBlur();
|
595 | }
|
596 |
|
597 | onDayMouseEnter(day) {
|
598 |
|
599 | if (this.isTouchDevice) return;
|
600 | const {
|
601 | startDate,
|
602 | endDate,
|
603 | focusedInput,
|
604 | getMinNightsForHoverDate,
|
605 | minimumNights,
|
606 | startDateOffset,
|
607 | endDateOffset,
|
608 | } = this.props;
|
609 |
|
610 | const {
|
611 | hoverDate,
|
612 | visibleDays,
|
613 | dateOffset,
|
614 | } = this.state;
|
615 |
|
616 | let nextDateOffset = null;
|
617 |
|
618 | if (focusedInput) {
|
619 | const hasOffset = startDateOffset || endDateOffset;
|
620 | let modifiers = {};
|
621 |
|
622 | if (hasOffset) {
|
623 | const start = getSelectedDateOffset(startDateOffset, day);
|
624 | const end = getSelectedDateOffset(endDateOffset, day, (rangeDay) => rangeDay.add(1, 'day'));
|
625 |
|
626 | nextDateOffset = {
|
627 | start,
|
628 | end,
|
629 | };
|
630 |
|
631 |
|
632 | if (dateOffset && dateOffset.start && dateOffset.end) {
|
633 | modifiers = this.deleteModifierFromRange(modifiers, dateOffset.start, dateOffset.end, 'hovered-offset');
|
634 | }
|
635 | modifiers = this.addModifierToRange(modifiers, start, end, 'hovered-offset');
|
636 | }
|
637 |
|
638 | if (!hasOffset) {
|
639 | modifiers = this.deleteModifier(modifiers, hoverDate, 'hovered');
|
640 | modifiers = this.addModifier(modifiers, day, 'hovered');
|
641 |
|
642 | if (startDate && !endDate && focusedInput === END_DATE) {
|
643 | if (isAfterDay(hoverDate, startDate)) {
|
644 | const endSpan = hoverDate.clone().add(1, 'day');
|
645 | modifiers = this.deleteModifierFromRange(modifiers, startDate, endSpan, 'hovered-span');
|
646 | }
|
647 |
|
648 | if (!this.isBlocked(day) && isAfterDay(day, startDate)) {
|
649 | const endSpan = day.clone().add(1, 'day');
|
650 | modifiers = this.addModifierToRange(modifiers, startDate, endSpan, 'hovered-span');
|
651 | }
|
652 | }
|
653 |
|
654 | if (!startDate && endDate && focusedInput === START_DATE) {
|
655 | if (isBeforeDay(hoverDate, endDate)) {
|
656 | modifiers = this.deleteModifierFromRange(modifiers, hoverDate, endDate, 'hovered-span');
|
657 | }
|
658 |
|
659 | if (!this.isBlocked(day) && isBeforeDay(day, endDate)) {
|
660 | modifiers = this.addModifierToRange(modifiers, day, endDate, 'hovered-span');
|
661 | }
|
662 | }
|
663 |
|
664 | if (startDate) {
|
665 | const startSpan = startDate.clone().add(1, 'day');
|
666 | const endSpan = startDate.clone().add(minimumNights + 1, 'days');
|
667 | modifiers = this.deleteModifierFromRange(modifiers, startSpan, endSpan, 'after-hovered-start');
|
668 |
|
669 | if (isSameDay(day, startDate)) {
|
670 | const newStartSpan = startDate.clone().add(1, 'day');
|
671 | const newEndSpan = startDate.clone().add(minimumNights + 1, 'days');
|
672 | modifiers = this.addModifierToRange(
|
673 | modifiers,
|
674 | newStartSpan,
|
675 | newEndSpan,
|
676 | 'after-hovered-start',
|
677 | );
|
678 | }
|
679 | }
|
680 |
|
681 | if (hoverDate && !this.isBlocked(hoverDate)) {
|
682 | const minNightsForPrevHoverDate = getMinNightsForHoverDate(hoverDate);
|
683 | if (minNightsForPrevHoverDate > 0 && focusedInput === START_DATE) {
|
684 | modifiers = this.deleteModifierFromRange(
|
685 | modifiers,
|
686 | hoverDate.clone().add(1, 'days'),
|
687 | hoverDate.clone().add(minNightsForPrevHoverDate, 'days'),
|
688 | 'hovered-start-blocked-minimum-nights',
|
689 | );
|
690 |
|
691 | modifiers = this.deleteModifier(
|
692 | modifiers,
|
693 | hoverDate.clone().add(minNightsForPrevHoverDate, 'days'),
|
694 | 'hovered-start-first-possible-end',
|
695 | );
|
696 | }
|
697 | }
|
698 |
|
699 | if (!this.isBlocked(day)) {
|
700 | const minNightsForHoverDate = getMinNightsForHoverDate(day);
|
701 | if (minNightsForHoverDate > 0 && focusedInput === START_DATE) {
|
702 | modifiers = this.addModifierToRange(
|
703 | modifiers,
|
704 | day.clone().add(1, 'days'),
|
705 | day.clone().add(minNightsForHoverDate, 'days'),
|
706 | 'hovered-start-blocked-minimum-nights',
|
707 | );
|
708 |
|
709 | modifiers = this.addModifier(
|
710 | modifiers,
|
711 | day.clone().add(minNightsForHoverDate, 'days'),
|
712 | 'hovered-start-first-possible-end',
|
713 | );
|
714 | }
|
715 | }
|
716 | }
|
717 |
|
718 | this.setState({
|
719 | hoverDate: day,
|
720 | dateOffset: nextDateOffset,
|
721 | visibleDays: {
|
722 | ...visibleDays,
|
723 | ...modifiers,
|
724 | },
|
725 | });
|
726 | }
|
727 | }
|
728 |
|
729 | onDayMouseLeave(day) {
|
730 | const {
|
731 | startDate,
|
732 | endDate,
|
733 | focusedInput,
|
734 | getMinNightsForHoverDate,
|
735 | minimumNights,
|
736 | } = this.props;
|
737 | const { hoverDate, visibleDays, dateOffset } = this.state;
|
738 | if (this.isTouchDevice || !hoverDate) return;
|
739 |
|
740 | let modifiers = {};
|
741 | modifiers = this.deleteModifier(modifiers, hoverDate, 'hovered');
|
742 |
|
743 | if (dateOffset) {
|
744 | modifiers = this.deleteModifierFromRange(modifiers, dateOffset.start, dateOffset.end, 'hovered-offset');
|
745 | }
|
746 |
|
747 | if (startDate && !endDate && isAfterDay(hoverDate, startDate)) {
|
748 | const endSpan = hoverDate.clone().add(1, 'day');
|
749 | modifiers = this.deleteModifierFromRange(modifiers, startDate, endSpan, 'hovered-span');
|
750 | }
|
751 |
|
752 | if (!startDate && endDate && isAfterDay(endDate, hoverDate)) {
|
753 | modifiers = this.deleteModifierFromRange(modifiers, hoverDate, endDate, 'hovered-span');
|
754 | }
|
755 |
|
756 | if (startDate && isSameDay(day, startDate)) {
|
757 | const startSpan = startDate.clone().add(1, 'day');
|
758 | const endSpan = startDate.clone().add(minimumNights + 1, 'days');
|
759 | modifiers = this.deleteModifierFromRange(modifiers, startSpan, endSpan, 'after-hovered-start');
|
760 | }
|
761 |
|
762 | if (!this.isBlocked(hoverDate)) {
|
763 | const minNightsForHoverDate = getMinNightsForHoverDate(hoverDate);
|
764 | if (minNightsForHoverDate > 0 && focusedInput === START_DATE) {
|
765 | modifiers = this.deleteModifierFromRange(
|
766 | modifiers,
|
767 | hoverDate.clone().add(1, 'days'),
|
768 | hoverDate.clone().add(minNightsForHoverDate, 'days'),
|
769 | 'hovered-start-blocked-minimum-nights',
|
770 | );
|
771 |
|
772 | modifiers = this.deleteModifier(
|
773 | modifiers,
|
774 | hoverDate.clone().add(minNightsForHoverDate, 'days'),
|
775 | 'hovered-start-first-possible-end',
|
776 | );
|
777 | }
|
778 | }
|
779 |
|
780 |
|
781 | this.setState({
|
782 | hoverDate: null,
|
783 | visibleDays: {
|
784 | ...visibleDays,
|
785 | ...modifiers,
|
786 | },
|
787 | });
|
788 | }
|
789 |
|
790 | onPrevMonthClick() {
|
791 | const {
|
792 | enableOutsideDays,
|
793 | maxDate,
|
794 | minDate,
|
795 | numberOfMonths,
|
796 | onPrevMonthClick,
|
797 | } = this.props;
|
798 | const { currentMonth, visibleDays } = this.state;
|
799 |
|
800 | const newVisibleDays = {};
|
801 | Object.keys(visibleDays).sort().slice(0, numberOfMonths + 1).forEach((month) => {
|
802 | newVisibleDays[month] = visibleDays[month];
|
803 | });
|
804 |
|
805 | const prevMonth = currentMonth.clone().subtract(2, 'months');
|
806 | const prevMonthVisibleDays = getVisibleDays(prevMonth, 1, enableOutsideDays, true);
|
807 |
|
808 | const newCurrentMonth = currentMonth.clone().subtract(1, 'month');
|
809 | this.setState({
|
810 | currentMonth: newCurrentMonth,
|
811 | disablePrev: this.shouldDisableMonthNavigation(minDate, newCurrentMonth),
|
812 | disableNext: this.shouldDisableMonthNavigation(maxDate, newCurrentMonth),
|
813 | visibleDays: {
|
814 | ...newVisibleDays,
|
815 | ...this.getModifiers(prevMonthVisibleDays),
|
816 | },
|
817 | }, () => {
|
818 | onPrevMonthClick(newCurrentMonth.clone());
|
819 | });
|
820 | }
|
821 |
|
822 | onNextMonthClick() {
|
823 | const {
|
824 | enableOutsideDays,
|
825 | maxDate,
|
826 | minDate,
|
827 | numberOfMonths,
|
828 | onNextMonthClick,
|
829 | } = this.props;
|
830 | const { currentMonth, visibleDays } = this.state;
|
831 |
|
832 | const newVisibleDays = {};
|
833 | Object.keys(visibleDays).sort().slice(1).forEach((month) => {
|
834 | newVisibleDays[month] = visibleDays[month];
|
835 | });
|
836 |
|
837 | const nextMonth = currentMonth.clone().add(numberOfMonths + 1, 'month');
|
838 | const nextMonthVisibleDays = getVisibleDays(nextMonth, 1, enableOutsideDays, true);
|
839 | const newCurrentMonth = currentMonth.clone().add(1, 'month');
|
840 | this.setState({
|
841 | currentMonth: newCurrentMonth,
|
842 | disablePrev: this.shouldDisableMonthNavigation(minDate, newCurrentMonth),
|
843 | disableNext: this.shouldDisableMonthNavigation(maxDate, newCurrentMonth),
|
844 | visibleDays: {
|
845 | ...newVisibleDays,
|
846 | ...this.getModifiers(nextMonthVisibleDays),
|
847 | },
|
848 | }, () => {
|
849 | onNextMonthClick(newCurrentMonth.clone());
|
850 | });
|
851 | }
|
852 |
|
853 | onMonthChange(newMonth) {
|
854 | const { numberOfMonths, enableOutsideDays, orientation } = this.props;
|
855 | const withoutTransitionMonths = orientation === VERTICAL_SCROLLABLE;
|
856 | const newVisibleDays = getVisibleDays(
|
857 | newMonth,
|
858 | numberOfMonths,
|
859 | enableOutsideDays,
|
860 | withoutTransitionMonths,
|
861 | );
|
862 |
|
863 | this.setState({
|
864 | currentMonth: newMonth.clone(),
|
865 | visibleDays: this.getModifiers(newVisibleDays),
|
866 | });
|
867 | }
|
868 |
|
869 | onYearChange(newMonth) {
|
870 | const { numberOfMonths, enableOutsideDays, orientation } = this.props;
|
871 | const withoutTransitionMonths = orientation === VERTICAL_SCROLLABLE;
|
872 | const newVisibleDays = getVisibleDays(
|
873 | newMonth,
|
874 | numberOfMonths,
|
875 | enableOutsideDays,
|
876 | withoutTransitionMonths,
|
877 | );
|
878 |
|
879 | this.setState({
|
880 | currentMonth: newMonth.clone(),
|
881 | visibleDays: this.getModifiers(newVisibleDays),
|
882 | });
|
883 | }
|
884 |
|
885 | onMultiplyScrollableMonths() {
|
886 | const { numberOfMonths, enableOutsideDays } = this.props;
|
887 | const { currentMonth, visibleDays } = this.state;
|
888 |
|
889 | const numberOfVisibleMonths = Object.keys(visibleDays).length;
|
890 | const nextMonth = currentMonth.clone().add(numberOfVisibleMonths, 'month');
|
891 | const newVisibleDays = getVisibleDays(nextMonth, numberOfMonths, enableOutsideDays, true);
|
892 |
|
893 | this.setState({
|
894 | visibleDays: {
|
895 | ...visibleDays,
|
896 | ...this.getModifiers(newVisibleDays),
|
897 | },
|
898 | });
|
899 | }
|
900 |
|
901 | getFirstFocusableDay(newMonth) {
|
902 | const {
|
903 | startDate,
|
904 | endDate,
|
905 | focusedInput,
|
906 | minimumNights,
|
907 | numberOfMonths,
|
908 | } = this.props;
|
909 |
|
910 | let focusedDate = newMonth.clone().startOf('month');
|
911 | if (focusedInput === START_DATE && startDate) {
|
912 | focusedDate = startDate.clone();
|
913 | } else if (focusedInput === END_DATE && !endDate && startDate) {
|
914 | focusedDate = startDate.clone().add(minimumNights, 'days');
|
915 | } else if (focusedInput === END_DATE && endDate) {
|
916 | focusedDate = endDate.clone();
|
917 | }
|
918 |
|
919 | if (this.isBlocked(focusedDate)) {
|
920 | const days = [];
|
921 | const lastVisibleDay = newMonth.clone().add(numberOfMonths - 1, 'months').endOf('month');
|
922 | let currentDay = focusedDate.clone();
|
923 | while (!isAfterDay(currentDay, lastVisibleDay)) {
|
924 | currentDay = currentDay.clone().add(1, 'day');
|
925 | days.push(currentDay);
|
926 | }
|
927 |
|
928 | const viableDays = days.filter((day) => !this.isBlocked(day));
|
929 |
|
930 | if (viableDays.length > 0) {
|
931 | ([focusedDate] = viableDays);
|
932 | }
|
933 | }
|
934 |
|
935 | return focusedDate;
|
936 | }
|
937 |
|
938 | getModifiers(visibleDays) {
|
939 | const modifiers = {};
|
940 | Object.keys(visibleDays).forEach((month) => {
|
941 | modifiers[month] = {};
|
942 | visibleDays[month].forEach((day) => {
|
943 | modifiers[month][toISODateString(day)] = this.getModifiersForDay(day);
|
944 | });
|
945 | });
|
946 |
|
947 | return modifiers;
|
948 | }
|
949 |
|
950 | getModifiersForDay(day) {
|
951 | return new Set(Object.keys(this.modifiers).filter((modifier) => this.modifiers[modifier](day)));
|
952 | }
|
953 |
|
954 | getStateForNewMonth(nextProps) {
|
955 | const {
|
956 | initialVisibleMonth,
|
957 | numberOfMonths,
|
958 | enableOutsideDays,
|
959 | orientation,
|
960 | startDate,
|
961 | } = nextProps;
|
962 | const initialVisibleMonthThunk = initialVisibleMonth || (
|
963 | startDate ? () => startDate : () => this.today
|
964 | );
|
965 | const currentMonth = initialVisibleMonthThunk();
|
966 | const withoutTransitionMonths = orientation === VERTICAL_SCROLLABLE;
|
967 | const visibleDays = this.getModifiers(getVisibleDays(
|
968 | currentMonth,
|
969 | numberOfMonths,
|
970 | enableOutsideDays,
|
971 | withoutTransitionMonths,
|
972 | ));
|
973 | return { currentMonth, visibleDays };
|
974 | }
|
975 |
|
976 | shouldDisableMonthNavigation(date, visibleMonth) {
|
977 | if (!date) return false;
|
978 |
|
979 | const {
|
980 | numberOfMonths,
|
981 | enableOutsideDays,
|
982 | } = this.props;
|
983 |
|
984 | return isDayVisible(date, visibleMonth, numberOfMonths, enableOutsideDays);
|
985 | }
|
986 |
|
987 | addModifier(updatedDays, day, modifier) {
|
988 | return addModifier(updatedDays, day, modifier, this.props, this.state);
|
989 | }
|
990 |
|
991 | addModifierToRange(updatedDays, start, end, modifier) {
|
992 | let days = updatedDays;
|
993 |
|
994 | let spanStart = start.clone();
|
995 | while (isBeforeDay(spanStart, end)) {
|
996 | days = this.addModifier(days, spanStart, modifier);
|
997 | spanStart = spanStart.clone().add(1, 'day');
|
998 | }
|
999 |
|
1000 | return days;
|
1001 | }
|
1002 |
|
1003 | deleteModifier(updatedDays, day, modifier) {
|
1004 | return deleteModifier(updatedDays, day, modifier, this.props, this.state);
|
1005 | }
|
1006 |
|
1007 | deleteModifierFromRange(updatedDays, start, end, modifier) {
|
1008 | let days = updatedDays;
|
1009 |
|
1010 | let spanStart = start.clone();
|
1011 | while (isBeforeDay(spanStart, end)) {
|
1012 | days = this.deleteModifier(days, spanStart, modifier);
|
1013 | spanStart = spanStart.clone().add(1, 'day');
|
1014 | }
|
1015 |
|
1016 | return days;
|
1017 | }
|
1018 |
|
1019 | doesNotMeetMinimumNights(day) {
|
1020 | const {
|
1021 | startDate,
|
1022 | isOutsideRange,
|
1023 | focusedInput,
|
1024 | minimumNights,
|
1025 | } = this.props;
|
1026 | if (focusedInput !== END_DATE) return false;
|
1027 |
|
1028 | if (startDate) {
|
1029 | const dayDiff = day.diff(startDate.clone().startOf('day').hour(12), 'days');
|
1030 | return dayDiff < minimumNights && dayDiff >= 0;
|
1031 | }
|
1032 | return isOutsideRange(moment(day).subtract(minimumNights, 'days'));
|
1033 | }
|
1034 |
|
1035 | doesNotMeetMinNightsForHoveredStartDate(day, hoverDate) {
|
1036 | const {
|
1037 | focusedInput,
|
1038 | getMinNightsForHoverDate,
|
1039 | } = this.props;
|
1040 | if (focusedInput !== END_DATE) return false;
|
1041 |
|
1042 | if (hoverDate && !this.isBlocked(hoverDate)) {
|
1043 | const minNights = getMinNightsForHoverDate(hoverDate);
|
1044 | const dayDiff = day.diff(hoverDate.clone().startOf('day').hour(12), 'days');
|
1045 | return dayDiff < minNights && dayDiff >= 0;
|
1046 | }
|
1047 | return false;
|
1048 | }
|
1049 |
|
1050 | isDayAfterHoveredStartDate(day) {
|
1051 | const { startDate, endDate, minimumNights } = this.props;
|
1052 | const { hoverDate } = this.state || {};
|
1053 | return !!startDate
|
1054 | && !endDate
|
1055 | && !this.isBlocked(day)
|
1056 | && isNextDay(hoverDate, day)
|
1057 | && minimumNights > 0
|
1058 | && isSameDay(hoverDate, startDate);
|
1059 | }
|
1060 |
|
1061 | isEndDate(day) {
|
1062 | const { endDate } = this.props;
|
1063 | return isSameDay(day, endDate);
|
1064 | }
|
1065 |
|
1066 | isHovered(day) {
|
1067 | const { hoverDate } = this.state || {};
|
1068 | const { focusedInput } = this.props;
|
1069 | return !!focusedInput && isSameDay(day, hoverDate);
|
1070 | }
|
1071 |
|
1072 | isInHoveredSpan(day) {
|
1073 | const { startDate, endDate } = this.props;
|
1074 | const { hoverDate } = this.state || {};
|
1075 |
|
1076 | const isForwardRange = !!startDate && !endDate && (
|
1077 | day.isBetween(startDate, hoverDate) || isSameDay(hoverDate, day)
|
1078 | );
|
1079 | const isBackwardRange = !!endDate && !startDate && (
|
1080 | day.isBetween(hoverDate, endDate) || isSameDay(hoverDate, day)
|
1081 | );
|
1082 |
|
1083 | const isValidDayHovered = hoverDate && !this.isBlocked(hoverDate);
|
1084 |
|
1085 | return (isForwardRange || isBackwardRange) && isValidDayHovered;
|
1086 | }
|
1087 |
|
1088 | isInSelectedSpan(day) {
|
1089 | const { startDate, endDate } = this.props;
|
1090 | return day.isBetween(startDate, endDate, 'days');
|
1091 | }
|
1092 |
|
1093 | isLastInRange(day) {
|
1094 | const { endDate } = this.props;
|
1095 | return this.isInSelectedSpan(day) && isNextDay(day, endDate);
|
1096 | }
|
1097 |
|
1098 | isStartDate(day) {
|
1099 | const { startDate } = this.props;
|
1100 | return isSameDay(day, startDate);
|
1101 | }
|
1102 |
|
1103 | isBlocked(day) {
|
1104 | const { isDayBlocked, isOutsideRange } = this.props;
|
1105 | return isDayBlocked(day) || isOutsideRange(day) || this.doesNotMeetMinimumNights(day);
|
1106 | }
|
1107 |
|
1108 | isToday(day) {
|
1109 | return isSameDay(day, this.today);
|
1110 | }
|
1111 |
|
1112 | isFirstDayOfWeek(day) {
|
1113 | const { firstDayOfWeek } = this.props;
|
1114 | return day.day() === (firstDayOfWeek || moment.localeData().firstDayOfWeek());
|
1115 | }
|
1116 |
|
1117 | isLastDayOfWeek(day) {
|
1118 | const { firstDayOfWeek } = this.props;
|
1119 | return day.day() === ((firstDayOfWeek || moment.localeData().firstDayOfWeek()) + 6) % 7;
|
1120 | }
|
1121 |
|
1122 | isFirstPossibleEndDateForHoveredStartDate(day, hoverDate) {
|
1123 | const { focusedInput, getMinNightsForHoverDate } = this.props;
|
1124 | if (focusedInput !== END_DATE || !hoverDate || this.isBlocked(hoverDate)) return false;
|
1125 | const minNights = getMinNightsForHoverDate(hoverDate);
|
1126 | const firstAvailableEndDate = hoverDate.clone().add(minNights, 'days');
|
1127 | return isSameDay(day, firstAvailableEndDate);
|
1128 | }
|
1129 |
|
1130 | render() {
|
1131 | const {
|
1132 | numberOfMonths,
|
1133 | orientation,
|
1134 | monthFormat,
|
1135 | renderMonthText,
|
1136 | renderWeekHeaderElement,
|
1137 | navPrev,
|
1138 | navNext,
|
1139 | noNavButtons,
|
1140 | onOutsideClick,
|
1141 | withPortal,
|
1142 | enableOutsideDays,
|
1143 | firstDayOfWeek,
|
1144 | renderKeyboardShortcutsButton,
|
1145 | hideKeyboardShortcutsPanel,
|
1146 | daySize,
|
1147 | focusedInput,
|
1148 | renderCalendarDay,
|
1149 | renderDayContents,
|
1150 | renderCalendarInfo,
|
1151 | renderMonthElement,
|
1152 | calendarInfoPosition,
|
1153 | onBlur,
|
1154 | onShiftTab,
|
1155 | onTab,
|
1156 | isFocused,
|
1157 | showKeyboardShortcuts,
|
1158 | isRTL,
|
1159 | weekDayFormat,
|
1160 | dayAriaLabelFormat,
|
1161 | verticalHeight,
|
1162 | noBorder,
|
1163 | transitionDuration,
|
1164 | verticalBorderSpacing,
|
1165 | horizontalMonthPadding,
|
1166 | } = this.props;
|
1167 |
|
1168 | const {
|
1169 | currentMonth,
|
1170 | phrases,
|
1171 | visibleDays,
|
1172 | disablePrev,
|
1173 | disableNext,
|
1174 | } = this.state;
|
1175 |
|
1176 | return (
|
1177 | <DayPicker
|
1178 | orientation={orientation}
|
1179 | enableOutsideDays={enableOutsideDays}
|
1180 | modifiers={visibleDays}
|
1181 | numberOfMonths={numberOfMonths}
|
1182 | onDayClick={this.onDayClick}
|
1183 | onDayMouseEnter={this.onDayMouseEnter}
|
1184 | onDayMouseLeave={this.onDayMouseLeave}
|
1185 | onPrevMonthClick={this.onPrevMonthClick}
|
1186 | onNextMonthClick={this.onNextMonthClick}
|
1187 | onMonthChange={this.onMonthChange}
|
1188 | onTab={onTab}
|
1189 | onShiftTab={onShiftTab}
|
1190 | onYearChange={this.onYearChange}
|
1191 | onMultiplyScrollableMonths={this.onMultiplyScrollableMonths}
|
1192 | monthFormat={monthFormat}
|
1193 | renderMonthText={renderMonthText}
|
1194 | renderWeekHeaderElement={renderWeekHeaderElement}
|
1195 | withPortal={withPortal}
|
1196 | hidden={!focusedInput}
|
1197 | initialVisibleMonth={() => currentMonth}
|
1198 | daySize={daySize}
|
1199 | onOutsideClick={onOutsideClick}
|
1200 | disablePrev={disablePrev}
|
1201 | disableNext={disableNext}
|
1202 | navPrev={navPrev}
|
1203 | navNext={navNext}
|
1204 | noNavButtons={noNavButtons}
|
1205 | renderCalendarDay={renderCalendarDay}
|
1206 | renderDayContents={renderDayContents}
|
1207 | renderCalendarInfo={renderCalendarInfo}
|
1208 | renderMonthElement={renderMonthElement}
|
1209 | renderKeyboardShortcutsButton={renderKeyboardShortcutsButton}
|
1210 | calendarInfoPosition={calendarInfoPosition}
|
1211 | firstDayOfWeek={firstDayOfWeek}
|
1212 | hideKeyboardShortcutsPanel={hideKeyboardShortcutsPanel}
|
1213 | isFocused={isFocused}
|
1214 | getFirstFocusableDay={this.getFirstFocusableDay}
|
1215 | onBlur={onBlur}
|
1216 | showKeyboardShortcuts={showKeyboardShortcuts}
|
1217 | phrases={phrases}
|
1218 | isRTL={isRTL}
|
1219 | weekDayFormat={weekDayFormat}
|
1220 | dayAriaLabelFormat={dayAriaLabelFormat}
|
1221 | verticalHeight={verticalHeight}
|
1222 | verticalBorderSpacing={verticalBorderSpacing}
|
1223 | noBorder={noBorder}
|
1224 | transitionDuration={transitionDuration}
|
1225 | horizontalMonthPadding={horizontalMonthPadding}
|
1226 | />
|
1227 | );
|
1228 | }
|
1229 | }
|
1230 |
|
1231 | DayPickerRangeController.propTypes = propTypes;
|
1232 | DayPickerRangeController.defaultProps = defaultProps;
|