@i-novus/ui-core
Version:
Базовые UI компоненты
98 lines (97 loc) • 4.91 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { forwardRef, useCallback, useLayoutEffect, useRef, useState } from 'react';
import ReactCalendar from 'react-calendar';
import classNames from 'classnames';
import { useConfigProvider } from '../../core';
import { Navigation } from './Navigation';
import { EChangeType } from './types';
import { TimePicker } from './Navigation/TimePicker';
const getWeekDayShortLabels = (locale, date) => {
return new Intl
.DateTimeFormat(locale || 'ru', { weekday: 'short' })
.format(date);
};
const monthShortNames = [
'Янв',
'Фев',
'Мар',
'Апр',
'Май',
'Июн',
'Июл',
'Авг',
'Сен',
'Окт',
'Ноя',
'Дек',
];
const getMonthShortName = (locale, date) => {
const monthIndex = date.getMonth();
return monthShortNames[monthIndex] || '';
};
const TODAY = new Date();
const BEGINNING_OF_CENTURY = new Date('1900').getFullYear();
const DEFAULT_VIEW = 'month';
const MIN_YEAR = BEGINNING_OF_CENTURY;
const MAX_YEAR = TODAY.getFullYear() + 100;
const prepareDate = (value, time) => {
const date = new Date(value);
date.setHours(Number(time.hours), Number(time.minutes), Number(time.seconds));
return date;
};
export const Calendar = forwardRef((props, ref) => {
const { className, prefix, locale = 'ru', activeStartDate, style, view = DEFAULT_VIEW, onSelect, onMouseEnter, onMouseLeave, minDate, maxDate, dateAccuracy, } = props;
const { getPrefix } = useConfigProvider();
const prefixCls = getPrefix(prefix);
const calendarContainerRef = useRef(null);
const [calendarInitialDate, setCalendarInitialDate] = useState(activeStartDate || TODAY);
const [userSelectedDate, setUserSelectedDate] = useState(activeStartDate || TODAY);
const [time, setTime] = useState({ hours: '0', minutes: '0', seconds: '0' });
const showTimePicker = !!dateAccuracy && ['minute', 'full'].includes(dateAccuracy);
// #region date select handlers
const handleChangeTime = useCallback((value) => {
setTime(value);
onSelect?.(prepareDate(userSelectedDate, value), { changedType: EChangeType.TIME });
}, [onSelect, userSelectedDate]);
const handleCalendarDateSelect = useCallback((date) => {
setUserSelectedDate((selectedDate) => {
if (date.toISOString() === selectedDate?.toISOString()) {
return selectedDate;
}
return date;
});
}, []);
const handleActiveStartDateChange = useCallback(({ action, activeStartDate }) => {
if ((action.startsWith('next') || action.startsWith('prev')) && activeStartDate) {
setCalendarInitialDate(activeStartDate);
}
}, []);
const handleClickMonth = useCallback((value) => {
handleCalendarDateSelect(value);
onSelect?.(prepareDate(value, time), { changedType: EChangeType.MONTH });
}, [handleCalendarDateSelect, onSelect, time]);
const handleChange = useCallback((value) => {
if (Array.isArray(value) || !value) {
return;
}
handleCalendarDateSelect(value);
onSelect?.(prepareDate(value, time), { changedType: EChangeType.DATE });
}, [handleCalendarDateSelect, onSelect, time]);
// #endregion
useLayoutEffect(() => {
if (!activeStartDate) {
return;
}
setTime({
hours: activeStartDate.getHours().toString(),
minutes: activeStartDate.getMinutes().toString(),
seconds: activeStartDate.getSeconds().toString(),
});
setUserSelectedDate(activeStartDate);
setCalendarInitialDate(activeStartDate);
}, [activeStartDate]);
return (_jsxs("div", { ref: calendarContainerRef, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, className: classNames(`${prefixCls}-calendar`, className), style: style, children: [_jsx(Navigation, { prefix: prefixCls, view: view, initialDate: calendarInitialDate, minYear: minDate?.getFullYear() ?? MIN_YEAR, maxYear: maxDate?.getFullYear() ?? MAX_YEAR, onActiveStartDateChange: handleActiveStartDateChange }), _jsx(ReactCalendar, { inputRef: ref, showNeighboringMonth: false, showNavigation: false, formatShortWeekday: getWeekDayShortLabels, formatMonth: getMonthShortName, locale: locale, className: (classNames(`${prefixCls}-react-calendar`, {
[`${prefixCls}-react-calendar--with-timepicker`]: showTimePicker,
})), activeStartDate: calendarInitialDate, value: userSelectedDate, view: view, minDate: minDate, maxDate: maxDate, onChange: handleChange, onClickMonth: handleClickMonth, onActiveStartDateChange: handleActiveStartDateChange }), showTimePicker && (_jsx(TimePicker, { prefix: prefixCls, value: time, onChange: handleChangeTime, dateAccuracy: dateAccuracy }))] }));
});
Calendar.displayName = 'Calendar';