UNPKG

@coreui/react-pro

Version:

UI Components Library for React.js

348 lines (345 loc) 16.9 kB
import React, { forwardRef, useRef, useState, useEffect } from 'react'; import PropTypes from 'prop-types'; import classNames from '../../_virtual/index.js'; import { CCalendarNavigation } from './CCalendarNavigation.js'; import { convertToDateObject, isSameDateAs, getSelectableDates, getCalendarDate, isDateDisabled, setTimeFromDate, getDateBySelectionType, isDisableDateInRange } from './utils.js'; import '../../node_modules/tslib/tslib.es6.js'; import '@popperjs/core'; import { useForkedRef } from '../../hooks/useForkedRef.js'; import { CCalendarPanel } from './CCalendarPanel.js'; const CCalendar = forwardRef(({ ariaNavNextMonthLabel = 'Next month', ariaNavNextYearLabel = 'Next year', ariaNavPrevMonthLabel = 'Previous month', ariaNavPrevYearLabel = 'Previous year', startDate, endDate, calendarDate = startDate || endDate || null, calendars = 1, className, dayFormat = 'numeric', disabledDates, firstDayOfWeek = 1, locale = 'default', maxDate, minDate, navigation = true, navNextIcon, navNextDoubleIcon, navPrevIcon, navPrevDoubleIcon, navYearFirst, range, selectAdjacementDays = false, selectEndDate, selectionType = 'day', showAdjacementDays = true, showWeekNumber = false, weekdayFormat = 2, weekNumbersLabel, onCalendarDateChange, onDateHover, onEndDateChange, onStartDateChange, onSelectEndChange, onViewChanged, }, ref) => { const calendarRef = useRef(null); const forkedRef = useForkedRef(ref, calendarRef); const [_calendarDate, setCalendarDate] = useState(null); useEffect(() => { const viewMap = { day: 'days', week: 'days', month: 'months', year: 'years', }; handleViewChange(viewMap[selectionType] || 'days'); }, [selectionType]); useEffect(() => { if (calendarDate === null) { setCalendarDate(new Date()); return; } if (calendarDate) { const date = convertToDateObject(calendarDate, selectionType); if (!isSameDateAs(_calendarDate, date)) { setCalendarDate(date); } } }, [calendarDate]); const [_startDate, setStartDate] = useState(startDate ? convertToDateObject(startDate, selectionType) : null); const [_endDate, setEndDate] = useState(endDate ? convertToDateObject(endDate, selectionType) : null); useEffect(() => { const date = startDate ? convertToDateObject(startDate, selectionType) : null; if ((date === null || date === void 0 ? void 0 : date.getTime()) !== (_startDate === null || _startDate === void 0 ? void 0 : _startDate.getTime())) { setStartDate(date); } }, [startDate]); useEffect(() => { const date = endDate ? convertToDateObject(endDate, selectionType) : null; if ((date === null || date === void 0 ? void 0 : date.getTime()) !== (_endDate === null || _endDate === void 0 ? void 0 : _endDate.getTime())) { setEndDate(date); } }, [endDate]); const [_hoverDate, setHoverDate] = useState(null); const [_maxDate, setMaxDate] = useState(maxDate ? convertToDateObject(maxDate, selectionType) : null); useEffect(() => { setMaxDate(maxDate ? convertToDateObject(maxDate, selectionType) : null); }, [maxDate]); const [_minDate, setMinDate] = useState(minDate ? convertToDateObject(minDate, selectionType) : null); useEffect(() => { setMinDate(minDate ? convertToDateObject(minDate, selectionType) : null); }, [minDate]); const [_selectEndDate, setSelectEndDate] = useState(selectEndDate); useEffect(() => { setSelectEndDate(selectEndDate); }, [selectEndDate]); const [view, setView] = useState('days'); const [focusOn, setFocusOn] = useState(); useEffect(() => { var _a; if (typeof focusOn === 'number') { const list = getSelectableDates(calendarRef.current); (_a = list[focusOn]) === null || _a === void 0 ? void 0 : _a.focus(); setFocusOn(undefined); } }, [view]); const setCalendarPage = (years, months = 0, setMonth) => { if (_calendarDate === null) { return; } const year = _calendarDate.getFullYear(); const month = _calendarDate.getMonth(); const d = new Date(year, month, 1); if (years) { d.setFullYear(d.getFullYear() + years); } if (months) { d.setMonth(d.getMonth() + months); } setCalendarDate(d); onCalendarDateChange === null || onCalendarDateChange === void 0 ? void 0 : onCalendarDateChange(d); }; const handleStartDateChange = (date) => { date = date ? convertToDateObject(date, selectionType) : null; if (date) { date = setTimeFromDate(date, _startDate); } setStartDate(date); onStartDateChange === null || onStartDateChange === void 0 ? void 0 : onStartDateChange(getDateBySelectionType(date, selectionType)); }; const handleEndDateChange = (date) => { date = date ? convertToDateObject(date, selectionType) : null; if (date) { date = setTimeFromDate(date, _endDate); } setEndDate(date); onEndDateChange === null || onEndDateChange === void 0 ? void 0 : onEndDateChange(getDateBySelectionType(date, selectionType)); }; const handleSelectEndDateChange = (value) => { setSelectEndDate(value); onSelectEndChange === null || onSelectEndChange === void 0 ? void 0 : onSelectEndChange(value); }; const handleViewChange = (value) => { setView(value); onViewChanged === null || onViewChanged === void 0 ? void 0 : onViewChanged(value); }; const handleCalendarClick = (date, index) => { const _date = new Date(date); if (view === 'days') { setCalendarDate(index ? new Date(_date.setMonth(_date.getMonth() - index)) : _date); } if (view === 'months' && selectionType !== 'month') { setCalendarDate(index ? new Date(_date.setMonth(_date.getMonth() - index)) : _date); handleViewChange('days'); return; } if (view === 'years' && selectionType !== 'year') { setCalendarDate(index ? new Date(_date.setFullYear(_date.getFullYear() - index)) : _date); handleViewChange('months'); return; } // Allow to change the calendarDate but not startDate or endDate if (isDateDisabled(date, _minDate, _maxDate, disabledDates)) { return; } if (range) { if (_selectEndDate) { handleSelectEndDateChange(false); if (_startDate && _startDate > date) { handleStartDateChange(null); handleEndDateChange(null); return; } if (isDisableDateInRange(_startDate, date, disabledDates)) { handleStartDateChange(null); handleEndDateChange(null); return; } handleEndDateChange(date); return; } if (_endDate && _endDate < date) { handleStartDateChange(null); handleEndDateChange(null); return; } if (isDisableDateInRange(date, _endDate, disabledDates)) { handleStartDateChange(null); handleEndDateChange(null); return; } handleSelectEndDateChange(true); handleStartDateChange(date); return; } handleStartDateChange(date); }; const handleCalendarKeyDown = (event, date, index) => { if (event.code === 'Space' || event.key === 'Enter') { event.preventDefault(); if ((view === 'months' && selectionType !== 'month') || (view === 'years' && selectionType !== 'year')) { setFocusOn(0); } handleCalendarClick(date, index); } if (event.key === 'ArrowRight' || event.key === 'ArrowLeft' || event.key === 'ArrowUp' || event.key === 'ArrowDown') { event.preventDefault(); if (_maxDate && date >= _maxDate && (event.key === 'ArrowRight' || event.key === 'ArrowDown')) { return; } if (_minDate && date <= _minDate && (event.key === 'ArrowLeft' || event.key === 'ArrowUp')) { return; } let element = event.target; if (selectionType === 'week' && element.tabIndex === -1) { element = element.closest('tr[tabindex="0"]'); } const list = getSelectableDates(calendarRef.current); const index = list.indexOf(element); const first = index === 0; const last = index === list.length - 1; const toBoundary = { start: index, end: list.length - (index + 1), }; const gap = { ArrowRight: 1, ArrowLeft: -1, ArrowUp: selectionType === 'week' && view === 'days' ? -1 : view === 'days' ? -7 : -3, ArrowDown: selectionType === 'week' && view === 'days' ? 1 : view === 'days' ? 7 : 3, }; if ((event.key === 'ArrowRight' && last) || (event.key === 'ArrowDown' && toBoundary['end'] < gap['ArrowDown']) || (event.key === 'ArrowLeft' && first) || (event.key === 'ArrowUp' && toBoundary['start'] < Math.abs(gap['ArrowUp']))) { if (view === 'days') { setCalendarPage(0, event.key === 'ArrowRight' || event.key === 'ArrowDown' ? 1 : -1); } if (view === 'months') { setCalendarPage(event.key === 'ArrowRight' || event.key === 'ArrowDown' ? 1 : -1); } if (view === 'years') { setCalendarPage(event.key === 'ArrowRight' || event.key === 'ArrowDown' ? 10 : -10); } setTimeout(() => { var _a, _b; const _list = getSelectableDates((_a = element.parentNode) === null || _a === void 0 ? void 0 : _a.parentNode); if (_list.length > 0 && event.key === 'ArrowRight') { _list[0].focus(); } if (_list.length > 0 && event.key === 'ArrowLeft') { (_b = _list.at(-1)) === null || _b === void 0 ? void 0 : _b.focus(); } if (_list.length > 0 && event.key === 'ArrowDown') { _list[gap['ArrowDown'] - (list.length - index)].focus(); } if (_list.length > 0 && event.key === 'ArrowUp') { _list[_list.length - (Math.abs(gap['ArrowUp']) + 1 - (index + 1))].focus(); } }, 1); return; } if (list[index + gap[event.key]].tabIndex === 0) { list[index + gap[event.key]].focus(); return; } for (let i = index; i < list.length; event.key === 'ArrowRight' || event.key === 'ArrowDown' ? i++ : i--) { if (list[i + gap[event.key]].tabIndex === 0) { list[i + gap[event.key]].focus(); break; } } } }; const handleCalendarMouseEnter = (date) => { if (isDateDisabled(date, _minDate, _maxDate, disabledDates)) { return; } date = setTimeFromDate(date, selectEndDate ? _endDate : _startDate); setHoverDate(date); if (date) { onDateHover === null || onDateHover === void 0 ? void 0 : onDateHover(getDateBySelectionType(date, selectionType)); } }; const handleCalendarMouseLeave = () => { setHoverDate(null); onDateHover === null || onDateHover === void 0 ? void 0 : onDateHover(null); }; const handleNavigationOnClick = (direction, double = false) => { if (direction === 'prev') { if (double) { setCalendarPage(view === 'years' ? -10 : -1); return; } if (view !== 'days') { setCalendarPage(-1); return; } setCalendarPage(0, -1); return; } if (direction === 'next') { if (double) { setCalendarPage(view === 'years' ? 10 : 1); return; } if (view !== 'days') { setCalendarPage(1); return; } setCalendarPage(0, 1); return; } }; return (React.createElement("div", { className: classNames('calendars', { [`select-${selectionType}`]: selectionType && view === 'days', 'show-week-numbers': showWeekNumber, }, className), ref: forkedRef }, _calendarDate && Array.from({ length: calendars }, (_, index) => { const calendarDate = getCalendarDate(_calendarDate, index, view); return (React.createElement("div", { className: classNames('calendar', view), key: index }, React.createElement(CCalendarNavigation, { ariaNavNextMonthLabel: ariaNavNextMonthLabel, ariaNavNextYearLabel: ariaNavNextYearLabel, ariaNavPrevMonthLabel: ariaNavPrevMonthLabel, ariaNavPrevYearLabel: ariaNavPrevYearLabel, calendarDate: calendarDate, locale: locale, navigation: navigation, navNextDoubleIcon: navNextDoubleIcon, navNextIcon: navNextIcon, navPrevDoubleIcon: navPrevDoubleIcon, navPrevIcon: navPrevIcon, navYearFirst: navYearFirst, onMonthClick: () => handleViewChange('months'), onNavigationClick: handleNavigationOnClick, onYearClick: () => handleViewChange('years'), view: view }), React.createElement(CCalendarPanel, { calendarDate: calendarDate, dayFormat: dayFormat, disabledDates: disabledDates, endDate: _endDate, firstDayOfWeek: firstDayOfWeek, hoverDate: _hoverDate, locale: locale, maxDate: _maxDate, minDate: _minDate, onCalendarClick: (date) => handleCalendarClick(date, index), onCalendarKeyDown: (event, date) => handleCalendarKeyDown(event, date, index), onCalendarMouseEnter: handleCalendarMouseEnter, onCalendarMouseLeave: handleCalendarMouseLeave, order: index, selectAdjacementDays: selectAdjacementDays, selectEndDate: _selectEndDate, selectionType: selectionType, showAdjacementDays: showAdjacementDays, showWeekNumber: showWeekNumber, startDate: _startDate, view: view, weekdayFormat: weekdayFormat, weekNumbersLabel: weekNumbersLabel }))); }))); }); CCalendar.propTypes = { ariaNavNextMonthLabel: PropTypes.string, ariaNavNextYearLabel: PropTypes.string, ariaNavPrevMonthLabel: PropTypes.string, ariaNavPrevYearLabel: PropTypes.string, className: PropTypes.string, calendarDate: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.string]), calendars: PropTypes.number, dayFormat: PropTypes.oneOfType([ PropTypes.func, PropTypes.oneOf(['2-digit', 'numeric']), ]), disabledDates: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.array, PropTypes.func]), endDate: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.string]), firstDayOfWeek: PropTypes.number, locale: PropTypes.string, maxDate: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.string]), minDate: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.string]), navigation: PropTypes.bool, navNextIcon: PropTypes.node, navNextDoubleIcon: PropTypes.node, navPrevIcon: PropTypes.node, navPrevDoubleIcon: PropTypes.node, navYearFirst: PropTypes.bool, range: PropTypes.bool, selectAdjacementDays: PropTypes.bool, selectEndDate: PropTypes.bool, selectionType: PropTypes.oneOf(['day', 'week', 'month', 'year']), showAdjacementDays: PropTypes.bool, showWeekNumber: PropTypes.bool, startDate: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.string]), weekdayFormat: PropTypes.oneOfType([ PropTypes.func, PropTypes.number, PropTypes.oneOf(['long', 'narrow', 'short']), ]), weekNumbersLabel: PropTypes.string, onDateHover: PropTypes.func, onCalendarDateChange: PropTypes.func, onEndDateChange: PropTypes.func, onSelectEndChange: PropTypes.func, onStartDateChange: PropTypes.func, onViewChanged: PropTypes.func, }; CCalendar.displayName = 'CCalendar'; export { CCalendar }; //# sourceMappingURL=CCalendar.js.map