@coreui/react-pro
Version:
UI Components Library for React.js
290 lines (287 loc) • 20.7 kB
JavaScript
import { __rest } from '../../node_modules/tslib/tslib.es6.js';
import React, { forwardRef, useRef, useState, useEffect } from 'react';
import classNames from '../../_virtual/index.js';
import PropTypes from 'prop-types';
import { l as libExports } from '../../_virtual/lib.js';
import { CButton } from '../button/CButton.js';
import { CCalendar } from '../calendar/CCalendar.js';
import { getLocalDateFromString, convertToDateObject, isDateDisabled, getDateBySelectionType } from '../calendar/utils.js';
import { CFormControlWrapper } from '../form/CFormControlWrapper.js';
import { CPicker } from '../picker/CPicker.js';
import { CTimePicker } from '../time-picker/CTimePicker.js';
import { useDebouncedCallback } from '../../hooks/useDebouncedCallback.js';
import '@popperjs/core';
import { getInputIdOrName } from './utils.js';
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
const CDateRangePicker = forwardRef((_a, ref) => {
var { ariaNavNextMonthLabel, ariaNavNextYearLabel, ariaNavPrevMonthLabel, ariaNavPrevYearLabel, calendars = 2, cancelButton = 'Cancel', cancelButtonColor = 'primary', cancelButtonSize = 'sm', cancelButtonVariant = 'ghost', className, cleaner = true, closeOnSelect = true, confirmButton = 'OK', confirmButtonColor = 'primary', confirmButtonSize = 'sm', confirmButtonVariant, dayFormat, disabled, disabledDates, endDate, feedback, feedbackInvalid, feedbackValid, firstDayOfWeek, footer, id, indicator = true, inputDateFormat, inputDateParse, inputOnChangeDelay = 750, inputReadOnly, invalid, label, locale = 'default', maxDate, minDate, name, navigation, navYearFirst, onEndDateChange, onHide, onStartDateChange, onShow, placeholder = ['Start date', 'End date'], portal = true, previewDateOnHover = true, range = true, ranges, rangesButtonsColor = 'secondary', rangesButtonsSize, rangesButtonsVariant = 'ghost', required, separator = true, selectAdjacementDays, selectionType = 'day', showAdjacementDays, showWeekNumber, size, startDate, text, timepicker, toggler, todayButton = 'Today', todayButtonColor = 'primary', todayButtonSize = 'sm', todayButtonVariant, tooltipFeedback, valid, visible, weekdayFormat, weekNumbersLabel, calendarDate = startDate || endDate || null } = _a, rest = __rest(_a, ["ariaNavNextMonthLabel", "ariaNavNextYearLabel", "ariaNavPrevMonthLabel", "ariaNavPrevYearLabel", "calendars", "cancelButton", "cancelButtonColor", "cancelButtonSize", "cancelButtonVariant", "className", "cleaner", "closeOnSelect", "confirmButton", "confirmButtonColor", "confirmButtonSize", "confirmButtonVariant", "dayFormat", "disabled", "disabledDates", "endDate", "feedback", "feedbackInvalid", "feedbackValid", "firstDayOfWeek", "footer", "id", "indicator", "inputDateFormat", "inputDateParse", "inputOnChangeDelay", "inputReadOnly", "invalid", "label", "locale", "maxDate", "minDate", "name", "navigation", "navYearFirst", "onEndDateChange", "onHide", "onStartDateChange", "onShow", "placeholder", "portal", "previewDateOnHover", "range", "ranges", "rangesButtonsColor", "rangesButtonsSize", "rangesButtonsVariant", "required", "separator", "selectAdjacementDays", "selectionType", "showAdjacementDays", "showWeekNumber", "size", "startDate", "text", "timepicker", "toggler", "todayButton", "todayButtonColor", "todayButtonSize", "todayButtonVariant", "tooltipFeedback", "valid", "visible", "weekdayFormat", "weekNumbersLabel", "calendarDate"]);
const inputEndRef = useRef(null);
const inputStartRef = useRef(null);
const formRef = useRef(null);
const [_calendarDate, setCalendarDate] = useState(calendarDate);
const [_endDate, setEndDate] = useState(endDate !== null && endDate !== void 0 ? endDate : null);
const [_maxDate, setMaxDate] = useState(maxDate !== null && maxDate !== void 0 ? maxDate : null);
const [_minDate, setMinDate] = useState(minDate !== null && minDate !== void 0 ? minDate : null);
const [_startDate, setStartDate] = useState(startDate !== null && startDate !== void 0 ? startDate : null);
const [_visible, setVisible] = useState(visible);
const [initialStartDate, setInitialStartDate] = useState(startDate !== null && startDate !== void 0 ? startDate : null);
const [initialEndDate, setInitialEndDate] = useState(endDate !== null && endDate !== void 0 ? endDate : null);
const [inputStartHoverValue, setInputStartHoverValue] = useState(null);
const [inputEndHoverValue, setInputEndHoverValue] = useState(null);
const [isValid, setIsValid] = useState(valid !== null && valid !== void 0 ? valid : (invalid === true ? false : undefined));
const [selectEndDate, setSelectEndDate] = useState(false);
useEffect(() => {
setIsValid(valid !== null && valid !== void 0 ? valid : (invalid === true ? false : undefined));
}, [valid, invalid]);
useEffect(() => {
if (startDate) {
setStartDate(startDate);
setInputValue(inputStartRef.current, startDate);
}
}, [startDate]);
useEffect(() => {
if (endDate) {
setEndDate(endDate);
setInputValue(inputEndRef.current, endDate);
}
}, [endDate]);
useEffect(() => {
if (maxDate) {
setMaxDate(maxDate);
}
}, [maxDate]);
useEffect(() => {
if (minDate) {
setMinDate(minDate);
}
}, [minDate]);
useEffect(() => {
if (inputStartRef.current && inputStartRef.current.form) {
formRef.current = inputStartRef.current.form;
}
}, [inputStartRef]);
useEffect(() => {
if (formRef.current) {
formRef.current.addEventListener('submit', (event) => {
setTimeout(() => handleFormValidation(event.target));
});
handleFormValidation(formRef.current);
}
}, [formRef, _startDate, _endDate]);
const formatDate = (date) => {
if (inputDateFormat) {
const convertedDate = date instanceof Date ? new Date(date) : convertToDateObject(date, selectionType);
if (!convertedDate ||
(convertedDate instanceof Date && Number.isNaN(convertedDate.getTime()))) {
return '';
}
return inputDateFormat(convertedDate);
}
if (selectionType !== 'day') {
return date;
}
const _date = new Date(date);
if (Number.isNaN(_date.getTime())) {
return '';
}
return timepicker ? _date.toLocaleString(locale) : _date.toLocaleDateString(locale);
};
const setInputValue = (el, date) => {
if (!el) {
return;
}
if (date) {
el.value = formatDate(date);
return;
}
el.value = '';
};
const handleDateHover = (date) => {
if (!previewDateOnHover) {
return;
}
if (selectEndDate) {
setInputEndHoverValue(date);
}
else {
setInputStartHoverValue(date);
}
};
const handleClear = (event) => {
event.stopPropagation();
setStartDate(null);
setEndDate(null);
setInputValue(inputStartRef.current, null);
setInputValue(inputEndRef.current, null);
onStartDateChange === null || onStartDateChange === void 0 ? void 0 : onStartDateChange(null);
onEndDateChange === null || onEndDateChange === void 0 ? void 0 : onEndDateChange(null);
};
const handleEndDateChange = (date) => {
setEndDate(date);
setInputValue(inputEndRef.current, date);
setInputEndHoverValue(null);
onEndDateChange === null || onEndDateChange === void 0 ? void 0 : onEndDateChange(date);
if (timepicker || footer) {
return;
}
if (closeOnSelect && _startDate !== null) {
setVisible(false);
}
};
const handleFormValidation = (form) => {
if (!form.classList.contains('was-validated')) {
return;
}
if ((range && _startDate && _endDate) || (!range && _startDate)) {
return setIsValid(true);
}
setIsValid(false);
};
const handleStartDateChange = (date) => {
setStartDate(date);
setInputValue(inputStartRef.current, date);
setInputStartHoverValue(null);
onStartDateChange === null || onStartDateChange === void 0 ? void 0 : onStartDateChange(date);
if (timepicker || footer) {
return;
}
if (closeOnSelect && !range) {
setVisible(false);
}
};
const handleOnChange = useDebouncedCallback((value, input) => {
let date = null;
if (inputDateParse) {
date = inputDateParse(value);
}
else if (selectionType === 'day') {
date = getLocalDateFromString(value, locale, timepicker);
}
else {
date = convertToDateObject(value, selectionType);
}
if (date instanceof Date &&
isDateDisabled(date, _minDate ? convertToDateObject(_minDate, selectionType) : null, _maxDate ? convertToDateObject(_maxDate, selectionType) : null, disabledDates)) {
return; // Don't update if date is disabled
}
const isStartInput = input === 'start';
const inputRef = isStartInput ? inputStartRef : inputEndRef;
const setDate = isStartInput ? setStartDate : setEndDate;
const onChange = isStartInput ? onStartDateChange : onEndDateChange;
const validDate = date !== null && date !== void 0 ? date : null;
let formatedDate = validDate;
// Update calendar date for valid dates
if (validDate instanceof Date && validDate.getTime()) {
if (selectionType !== 'day') {
formatedDate = getDateBySelectionType(validDate, selectionType);
}
setCalendarDate(formatedDate);
setInputValue(inputRef.current, formatedDate);
}
// Update state and input
setDate(formatedDate);
onChange === null || onChange === void 0 ? void 0 : onChange(formatedDate);
}, inputOnChangeDelay);
const renderInput = (type) => {
const isStart = type === 'start';
const hoverValue = isStart ? inputStartHoverValue : inputEndHoverValue;
const inputRef = isStart ? inputStartRef : inputEndRef;
const placeholderText = isStart
? Array.isArray(placeholder)
? placeholder[0]
: placeholder
: placeholder[1];
const inputElement = (React.createElement("input", Object.assign({ autoComplete: "off", className: classNames('date-picker-input', {
hover: hoverValue,
}), disabled: disabled }, (id && { id: getInputIdOrName(id, range, type) }), (name && { name: getInputIdOrName(name, range, type) }), (id &&
!Array.isArray(id) &&
!name && {
name: isStart ? (range ? `${id}-start-date` : `${id}-date`) : `${id}-end-date`,
}), { placeholder: placeholderText, readOnly: inputReadOnly, required: required, onChange: (event) => {
handleOnChange(event.target.value, type);
}, onClick: () => setSelectEndDate(!isStart), ref: inputRef })));
if (previewDateOnHover && !disabled) {
return (React.createElement("div", { className: "date-picker-input-wrapper" },
inputElement,
hoverValue && (React.createElement("input", { className: "date-picker-input date-picker-input-preview", readOnly: true, value: formatDate(hoverValue) }))));
}
return inputElement;
};
const InputGroup = () => (React.createElement("div", { className: "date-picker-input-group" },
renderInput('start'),
range && separator !== false && React.createElement("div", { className: "date-picker-separator" }),
range && renderInput('end'),
indicator &&
(typeof indicator === 'boolean' ? (React.createElement("div", Object.assign({ className: "date-picker-indicator" }, (!disabled && {
onClick: () => setVisible(!_visible),
onKeyDown: (event) => {
if (event.key === 'Enter') {
setVisible(!_visible);
}
},
tabIndex: 0,
})))) : (indicator)),
cleaner &&
(_startDate || _endDate) &&
(typeof cleaner === 'boolean' ? (React.createElement("div", { className: "date-picker-cleaner", onClick: (event) => handleClear(event) })) : (React.isValidElement(cleaner) &&
React.cloneElement(cleaner, {
onClick: (event) => handleClear(event),
})))));
return (React.createElement(CFormControlWrapper, Object.assign({ describedby: rest['aria-describedby'], feedback: feedback, feedbackInvalid: feedbackInvalid, feedbackValid: feedbackValid }, (id && !Array.isArray(id) && { id: id }), { invalid: isValid === false ? true : false, label: label, text: text, tooltipFeedback: tooltipFeedback, valid: isValid }),
React.createElement(CPicker, Object.assign({ className: classNames('date-picker', {
[`date-picker-${size}`]: size,
disabled: disabled,
'is-invalid': isValid === false ? true : false,
'is-valid': isValid,
}, className), disabled: disabled, dropdownClassNames: "date-picker-dropdown", footer: footer || timepicker, footerContent: React.createElement("div", { className: "date-picker-footer" },
todayButton && (React.createElement(CButton, { className: "me-auto", color: todayButtonColor, size: todayButtonSize, variant: todayButtonVariant, onClick: () => {
const date = new Date();
handleStartDateChange(date);
if (range)
handleEndDateChange(date);
setCalendarDate(date);
} }, todayButton)),
cancelButton && (React.createElement(CButton, { color: cancelButtonColor, size: cancelButtonSize, variant: cancelButtonVariant, onClick: () => {
handleStartDateChange(initialStartDate);
if (range)
handleEndDateChange(initialEndDate);
setVisible(false);
} }, cancelButton)),
confirmButton && (React.createElement(CButton, { color: confirmButtonColor, size: confirmButtonSize, variant: confirmButtonVariant, onClick: () => {
setVisible(false);
} }, confirmButton))), toggler: toggler !== null && toggler !== void 0 ? toggler : InputGroup(), portal: portal, onHide: () => {
setVisible(false);
onHide === null || onHide === void 0 ? void 0 : onHide();
}, onShow: () => {
setInitialStartDate(_startDate);
setInitialEndDate(_endDate);
setVisible(true);
onShow === null || onShow === void 0 ? void 0 : onShow();
}, visible: _visible }, rest, { ref: ref }),
React.createElement("div", { className: "date-picker-body" },
ranges && (React.createElement("div", { className: "date-picker-ranges" }, Object.keys(ranges).map((key, index) => (React.createElement(CButton, { color: rangesButtonsColor, key: index, onClick: () => {
handleStartDateChange(ranges[key][0]);
handleEndDateChange(ranges[key][1]);
}, size: rangesButtonsSize, variant: rangesButtonsVariant }, key))))),
React.createElement(CCalendar, { ariaNavNextMonthLabel: ariaNavNextMonthLabel, ariaNavNextYearLabel: ariaNavNextYearLabel, ariaNavPrevMonthLabel: ariaNavPrevMonthLabel, ariaNavPrevYearLabel: ariaNavPrevYearLabel, calendarDate: _calendarDate, calendars: libExports.isMobile ? 1 : calendars, className: "date-picker-calendars", dayFormat: dayFormat, disabledDates: disabledDates, endDate: _endDate, firstDayOfWeek: firstDayOfWeek, locale: locale, maxDate: _maxDate, minDate: _minDate, navigation: navigation, navYearFirst: navYearFirst, range: range, selectAdjacementDays: selectAdjacementDays, selectEndDate: selectEndDate, selectionType: selectionType, showAdjacementDays: showAdjacementDays, showWeekNumber: showWeekNumber, startDate: _startDate, weekdayFormat: weekdayFormat, weekNumbersLabel: weekNumbersLabel, onDateHover: (date) => handleDateHover(date), onCalendarDateChange: (date) => setCalendarDate(date), onStartDateChange: (date) => handleStartDateChange(date), onEndDateChange: (date) => handleEndDateChange(date), onSelectEndChange: (value) => setSelectEndDate(value) }),
timepicker && (React.createElement("div", { className: "date-picker-timepickers" }, (libExports.isMobile && range) || (range && calendars === 1) ? (React.createElement(React.Fragment, null,
React.createElement(CTimePicker, { container: "inline", disabled: _startDate === null ? true : false, locale: locale, onTimeChange: (_, __, date) => date && handleStartDateChange(date), time: _startDate && new Date(_startDate), variant: "select" }),
React.createElement(CTimePicker, { container: "inline", disabled: _endDate === null ? true : false, locale: locale, onTimeChange: (_, __, date) => date && handleEndDateChange(date), time: _endDate && new Date(_endDate), variant: "select" }))) : (Array.from({ length: calendars }).map((_, index) => (React.createElement(CTimePicker, { container: "inline", disabled: index === 0
? _startDate === null
? true
: false
: _endDate === null
? true
: false, key: index, locale: locale, onTimeChange: (_, __, date) => index === 0
? date && handleStartDateChange(date)
: date && handleEndDateChange(date), time: index === 0
? _startDate && new Date(_startDate)
: _endDate && new Date(_endDate), variant: "select" }))))))))));
});
CDateRangePicker.displayName = 'CDateRangePicker';
CDateRangePicker.propTypes = Object.assign(Object.assign(Object.assign(Object.assign({}, CCalendar.propTypes), CFormControlWrapper.propTypes), CPicker.propTypes), { cancelButton: PropTypes.oneOfType([PropTypes.bool, PropTypes.node]), cancelButtonColor: (_a = CButton.propTypes) === null || _a === void 0 ? void 0 : _a.color, cancelButtonSize: (_b = CButton.propTypes) === null || _b === void 0 ? void 0 : _b.size, cancelButtonVariant: (_c = CButton.propTypes) === null || _c === void 0 ? void 0 : _c.variant, calendars: PropTypes.number, className: PropTypes.string, cleaner: PropTypes.bool, closeOnSelect: PropTypes.bool, confirmButton: PropTypes.oneOfType([PropTypes.bool, PropTypes.node]), confirmButtonColor: (_d = CButton.propTypes) === null || _d === void 0 ? void 0 : _d.color, confirmButtonSize: (_e = CButton.propTypes) === null || _e === void 0 ? void 0 : _e.size, confirmButtonVariant: (_f = CButton.propTypes) === null || _f === void 0 ? void 0 : _f.variant, id: PropTypes.oneOfType([PropTypes.string, PropTypes.any]), indicator: PropTypes.oneOfType([PropTypes.bool, PropTypes.node]), inputDateFormat: PropTypes.func, inputDateParse: PropTypes.func, inputOnChangeDelay: PropTypes.number, inputReadOnly: PropTypes.bool, name: PropTypes.oneOfType([PropTypes.string, PropTypes.any]), placeholder: PropTypes.oneOfType([
PropTypes.string,
PropTypes.arrayOf(PropTypes.string.isRequired),
]), previewDateOnHover: PropTypes.bool, range: PropTypes.bool, ranges: PropTypes.object, rangesButtonsColor: (_g = CButton.propTypes) === null || _g === void 0 ? void 0 : _g.color, rangesButtonsSize: (_h = CButton.propTypes) === null || _h === void 0 ? void 0 : _h.size, rangesButtonsVariant: (_j = CButton.propTypes) === null || _j === void 0 ? void 0 : _j.variant, required: PropTypes.bool, separator: PropTypes.oneOfType([PropTypes.bool, PropTypes.node]), size: PropTypes.oneOf(['sm', 'lg']), timepicker: PropTypes.bool, todayButton: PropTypes.oneOfType([PropTypes.bool, PropTypes.node]), todayButtonColor: (_k = CButton.propTypes) === null || _k === void 0 ? void 0 : _k.color, todayButtonSize: (_l = CButton.propTypes) === null || _l === void 0 ? void 0 : _l.size, todayButtonVariant: (_m = CButton.propTypes) === null || _m === void 0 ? void 0 : _m.variant });
export { CDateRangePicker };
//# sourceMappingURL=CDateRangePicker.js.map