UNPKG

@blueprintjs/datetime

Version:

Components for interacting with dates and times

192 lines 10.6 kB
"use strict"; /* * Copyright 2023 Palantir Technologies, Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.NonContiguousDayRangePicker = void 0; const tslib_1 = require("tslib"); const React = tslib_1.__importStar(require("react")); const react_day_picker_1 = require("react-day-picker"); const core_1 = require("@blueprintjs/core"); const common_1 = require("../../common"); const dateRangeSelectionStrategy_1 = require("../../common/dateRangeSelectionStrategy"); const monthAndYear_1 = require("../../common/monthAndYear"); const reactDayPickerUtils_1 = require("../../common/reactDayPickerUtils"); const datePickerCaption_1 = require("../react-day-picker/datePickerCaption"); /** * Date range picker with two calendars which can move independently of each other. */ const NonContiguousDayRangePicker = ({ allowSingleDayRange, boundaryToModify, dayPickerEventHandlers, dayPickerProps, initialMonthAndYear, locale, maxDate, minDate, onRangeSelect, value, }) => { const { displayMonths, handleLeftMonthChange, handleRightMonthChange } = useNonContiguousCalendarViews(initialMonthAndYear, value, dayPickerProps === null || dayPickerProps === void 0 ? void 0 : dayPickerProps.onMonthChange, minDate, maxDate); const handleDaySelect = React.useCallback((range, selectedDay, activeModifiers, e) => { var _a; (_a = dayPickerProps === null || dayPickerProps === void 0 ? void 0 : dayPickerProps.onSelect) === null || _a === void 0 ? void 0 : _a.call(dayPickerProps, range, selectedDay, activeModifiers, e); if (activeModifiers.disabled) { return; } const { dateRange: nextValue, boundary } = dateRangeSelectionStrategy_1.DateRangeSelectionStrategy.getNextState(value, selectedDay, allowSingleDayRange, boundaryToModify); onRangeSelect(nextValue, selectedDay, boundary); }, [allowSingleDayRange, boundaryToModify, dayPickerProps, onRangeSelect, value]); // props applied to both the left and right calendars const commonDayPickerProps = { locale, mode: "range", showOutsideDays: true, ...dayPickerProps, ...dayPickerEventHandlers, components: { Caption: datePickerCaption_1.DatePickerCaption, ...dayPickerProps === null || dayPickerProps === void 0 ? void 0 : dayPickerProps.components, }, onSelect: handleDaySelect, selected: (0, reactDayPickerUtils_1.dateRangeToDayPickerRange)(value), }; return (React.createElement("div", { className: common_1.Classes.DATERANGEPICKER_CALENDARS }, React.createElement(react_day_picker_1.DayPicker, { key: "left", ...commonDayPickerProps, fromDate: minDate, month: displayMonths.left.getFullDate(), numberOfMonths: 1, onMonthChange: handleLeftMonthChange, toMonth: common_1.DateUtils.getDatePreviousMonth(maxDate) }), React.createElement(react_day_picker_1.DayPicker, { key: "right", ...commonDayPickerProps, fromMonth: common_1.DateUtils.getDateNextMonth(minDate), month: displayMonths.right.getFullDate(), numberOfMonths: 1, onMonthChange: handleRightMonthChange, toDate: maxDate }))); }; exports.NonContiguousDayRangePicker = NonContiguousDayRangePicker; exports.NonContiguousDayRangePicker.displayName = `${core_1.DISPLAYNAME_PREFIX}.NonContiguousDayRangePicker`; /** * State management and navigation event handlers for two (left and right) non-contiguous calendar views. * * @param initialMonthAndYear initial month and year to display in the left calendar * @param selectedRange currently selected date range * @param userOnMonthChange custom `dayPickerProps.onMonthChange` handler supplied by users of `DateRangePicker` */ function useNonContiguousCalendarViews(initialMonthAndYear, selectedRange, userOnMonthChange, minDate, maxDate) { // show the selected end date's encompassing month in the right view if // the calendars don't have to be contiguous. // if left view and right view months are the same, show next month in the right view. const [views, setViews] = React.useState({ left: initialMonthAndYear, right: getInitialRightView(selectedRange[1], initialMonthAndYear), }); React.useEffect(() => { if (selectedRange == null) { return; } setViews(({ left, right }) => { let newLeftView = left.clone(); let newRightView = right.clone(); const nextValueStartView = monthAndYear_1.MonthAndYear.fromDate(selectedRange[0]); const nextValueEndView = monthAndYear_1.MonthAndYear.fromDate(selectedRange[1]); if (nextValueStartView == null && nextValueEndView != null) { // Only end date selected. // If the newly selected end date isn't in either of the displayed months, then // - set the right DayPicker to the month of the selected end date // - ensure the left DayPicker is before the right, changing if needed if (!nextValueEndView.isSame(newLeftView) && !nextValueEndView.isSame(newRightView)) { newRightView = nextValueEndView; if (!newLeftView.isBefore(newRightView)) { newLeftView = newRightView.getPreviousMonth(); } } } else if (nextValueStartView != null && nextValueEndView == null) { // Only start date selected. // If the newly selected start date isn't in either of the displayed months, then // - set the left DayPicker to the month of the selected start date // - ensure the right DayPicker is before the left, changing if needed if (!nextValueStartView.isSame(newLeftView) && !nextValueStartView.isSame(newRightView)) { newLeftView = nextValueStartView; if (!newRightView.isAfter(newLeftView)) { newRightView = newLeftView.getNextMonth(); } } } else if (nextValueStartView != null && nextValueEndView != null) { // Both start and end date months are identical // If the selected month isn't in either of the displayed months, then // - set the left DayPicker to be the selected month // - set the right DayPicker to +1 if (nextValueStartView.isSame(nextValueEndView)) { if (newLeftView.isSame(nextValueStartView) || newRightView.isSame(nextValueStartView)) { // do nothing } else { newLeftView = nextValueStartView; newRightView = nextValueStartView.getNextMonth(); } } else { // Different start and end date months, adjust display months. if (!newLeftView.isSame(nextValueStartView)) { newLeftView = nextValueStartView; newRightView = nextValueStartView.getNextMonth(); } if (!newRightView.isSame(nextValueEndView)) { newRightView = nextValueEndView; } } } return { left: newLeftView, right: newRightView }; }); }, [setViews, selectedRange]); const handleLeftMonthChange = React.useCallback((newDate) => { const newLeftView = monthAndYear_1.MonthAndYear.fromDate(newDate); if (newLeftView == null) { return; } setViews(({ right }) => { let newRightView = right.clone(); if (!newLeftView.isBefore(newRightView)) { newRightView = newLeftView.getNextMonth(); } const [leftView, rightView] = getBoundedViews(newLeftView, newRightView, minDate, maxDate); userOnMonthChange === null || userOnMonthChange === void 0 ? void 0 : userOnMonthChange(newLeftView.getFullDate()); return { left: leftView, right: rightView }; }); }, [minDate, maxDate, setViews, userOnMonthChange]); const handleRightMonthChange = React.useCallback((newDate) => { const newRightView = monthAndYear_1.MonthAndYear.fromDate(newDate); if (newRightView == null) { return; } setViews(({ left }) => { let newLeftView = left.clone(); if (!newRightView.isAfter(newLeftView)) { newLeftView = newRightView.getPreviousMonth(); } const [leftView, rightView] = getBoundedViews(newLeftView, newRightView, minDate, maxDate); userOnMonthChange === null || userOnMonthChange === void 0 ? void 0 : userOnMonthChange(newRightView.getFullDate()); return { left: leftView, right: rightView }; }); }, [minDate, maxDate, setViews, userOnMonthChange]); return { displayMonths: views, handleLeftMonthChange, handleRightMonthChange, }; } function getBoundedViews(leftView, rightView, minDate, maxDate) { const minView = monthAndYear_1.MonthAndYear.fromDate(minDate !== null && minDate !== void 0 ? minDate : null); if (minView != null && leftView.isBefore(minView)) { return [minView, minView.getNextMonth()]; } const maxView = monthAndYear_1.MonthAndYear.fromDate(maxDate !== null && maxDate !== void 0 ? maxDate : null); if (maxView != null && rightView.isAfter(maxView)) { return [maxView.getPreviousMonth(), maxView]; } return [leftView, rightView]; } function getInitialRightView(selectedRangeEnd, leftView) { const rightView = monthAndYear_1.MonthAndYear.fromDate(selectedRangeEnd); if (rightView === undefined || rightView.isSameMonth(leftView)) { return leftView.getNextMonth(); } return rightView; } //# sourceMappingURL=nonContiguousDayRangePicker.js.map