@alfalab/core-components-calendar-range 7.3.28 → 7.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/components/divider/Component.js +1 -1
  2. package/components/divider/index.css +8 -8
  3. package/esm/components/divider/Component.js +1 -1
  4. package/esm/components/divider/index.css +8 -8
  5. package/esm/index.module-c4c20f61.js +4 -0
  6. package/esm/views/index.css +7 -7
  7. package/esm/views/popover.js +1 -1
  8. package/esm/views/static.js +1 -1
  9. package/index.module-818eae0d.js +6 -0
  10. package/modern/components/divider/Component.js +1 -1
  11. package/modern/components/divider/index.css +8 -8
  12. package/modern/index.module-0f4ffc4a.js +4 -0
  13. package/modern/views/index.css +7 -7
  14. package/modern/views/popover.js +1 -1
  15. package/modern/views/static.js +1 -1
  16. package/moderncssm/Component.d.ts +90 -0
  17. package/moderncssm/Component.js +10 -0
  18. package/moderncssm/components/divider/Component.d.ts +8 -0
  19. package/moderncssm/components/divider/Component.js +14 -0
  20. package/moderncssm/components/divider/index.d.ts +1 -0
  21. package/moderncssm/components/divider/index.js +1 -0
  22. package/moderncssm/components/divider/index.module.css +55 -0
  23. package/moderncssm/hooks.d.ts +28 -0
  24. package/moderncssm/hooks.js +134 -0
  25. package/moderncssm/index.d.ts +1 -0
  26. package/moderncssm/index.js +1 -0
  27. package/moderncssm/utils.d.ts +2 -0
  28. package/moderncssm/utils.js +3 -0
  29. package/moderncssm/views/index.module.css +42 -0
  30. package/moderncssm/views/popover.d.ts +5 -0
  31. package/moderncssm/views/popover.js +128 -0
  32. package/moderncssm/views/static.d.ts +10 -0
  33. package/moderncssm/views/static.js +176 -0
  34. package/package.json +6 -6
  35. package/src/components/divider/index.module.css +1 -1
  36. package/src/views/index.module.css +1 -1
  37. package/views/index.css +7 -7
  38. package/views/popover.js +1 -1
  39. package/views/static.js +1 -1
  40. package/esm/index.module-6b92c205.js +0 -4
  41. package/index.module-ebe5324e.js +0 -6
  42. package/modern/index.module-4b1345e2.js +0 -4
@@ -0,0 +1,55 @@
1
+ /* */
2
+ :root {
3
+
4
+ /* Кнопки выбора месяцев и годов */
5
+
6
+ /* Шапка */
7
+
8
+ /* День */
9
+
10
+ /* today */
11
+
12
+ /* highlighted */
13
+
14
+ /* holidays */
15
+
16
+ /* range */
17
+
18
+ /* selected */
19
+
20
+ /* disabled */
21
+
22
+ /* marker */
23
+ }
24
+ .component {
25
+ display: flex;
26
+ align-items: center;
27
+ justify-content: center;
28
+ width: 16px;
29
+ margin: 0 var(--gap-8)
30
+ }
31
+ .component:after {
32
+ content: '';
33
+ display: block;
34
+ width: 100%;
35
+ height: 1px;
36
+ background-color: var(--color-light-neutral-translucent-1300);
37
+ }
38
+ .outer {
39
+ position: relative;
40
+
41
+ /* FormControl .above height + margin-bottom */
42
+ top: 24px;
43
+ }
44
+ .s {
45
+ height: var(--size-s-height);
46
+ }
47
+ .m {
48
+ height: var(--size-m-height);
49
+ }
50
+ .l {
51
+ height: var(--size-l-height);
52
+ }
53
+ .xl {
54
+ height: var(--size-xl-height);
55
+ }
@@ -0,0 +1,28 @@
1
+ declare function usePopoverViewMonthes({ dateFrom, dateTo, defaultMonth, resetKey, }: {
2
+ defaultMonth: number;
3
+ dateFrom: number | null;
4
+ dateTo: number | null;
5
+ resetKey?: number;
6
+ }): {
7
+ monthFrom: number | undefined;
8
+ monthTo: number | undefined;
9
+ handleMonthFromChange: (newMonthFrom: number) => void;
10
+ handleMonthToChange: (newMonthTo: number) => void;
11
+ };
12
+ declare function useStaticViewMonthes({ selectedFrom, selectedTo, defaultMonth, defaultMonthPosition, }: {
13
+ selectedFrom?: number;
14
+ selectedTo?: number;
15
+ defaultMonth: number;
16
+ defaultMonthPosition?: 'left' | 'right';
17
+ }): {
18
+ monthFrom: number;
19
+ monthTo: number;
20
+ handleMonthFromChange: (newMonthFrom: number) => void;
21
+ handleMonthToChange: (newMonthTo: number) => void;
22
+ };
23
+ declare function useSelectionProps(from?: number, to?: number, highlighted?: number): {
24
+ rangeComplete: boolean;
25
+ selectedFrom: number | undefined;
26
+ selectedTo: number | undefined;
27
+ };
28
+ export { usePopoverViewMonthes, useStaticViewMonthes, useSelectionProps };
@@ -0,0 +1,134 @@
1
+ import { useState, useCallback, useEffect, useMemo } from 'react';
2
+ import addMonths from 'date-fns/addMonths';
3
+ import isEqual from 'date-fns/isEqual';
4
+ import max from 'date-fns/max';
5
+ import min from 'date-fns/min';
6
+ import startOfMonth from 'date-fns/startOfMonth';
7
+ import subMonths from 'date-fns/subMonths';
8
+
9
+ function usePopoverViewMonthes({ dateFrom, dateTo, defaultMonth, resetKey, }) {
10
+ const [monthFrom, setMonthFrom] = useState();
11
+ const [monthTo, setMonthTo] = useState();
12
+ const handleMonthFromChange = useCallback((newMonthFrom) => {
13
+ setMonthFrom(newMonthFrom);
14
+ if (!dateTo) {
15
+ setMonthTo(newMonthFrom);
16
+ }
17
+ }, [dateTo]);
18
+ const handleMonthToChange = useCallback((newMonthTo) => {
19
+ setMonthTo(newMonthTo);
20
+ if (!dateFrom) {
21
+ setMonthFrom(newMonthTo);
22
+ }
23
+ }, [dateFrom]);
24
+ useEffect(() => {
25
+ setMonthFrom(dateFrom ? startOfMonth(dateFrom).getTime() : defaultMonth);
26
+ }, [defaultMonth, dateFrom, resetKey]);
27
+ useEffect(() => {
28
+ setMonthTo(dateTo ? startOfMonth(dateTo).getTime() : monthFrom);
29
+ // eslint-disable-next-line react-hooks/exhaustive-deps
30
+ }, [dateTo, resetKey]);
31
+ return {
32
+ monthFrom,
33
+ monthTo,
34
+ handleMonthFromChange,
35
+ handleMonthToChange,
36
+ };
37
+ }
38
+ function useStaticViewMonthes({ selectedFrom, selectedTo, defaultMonth, defaultMonthPosition, }) {
39
+ /**
40
+ * Если указана начальная дата — левый месяц равен ей, иначе используется дата конца.
41
+ * Если обе даты не указаны, то используется дефолтный месяц
42
+ */
43
+ let initialMonthFrom = useMemo(() => startOfMonth(selectedFrom || selectedTo || defaultMonth).getTime(),
44
+ // eslint-disable-next-line react-hooks/exhaustive-deps
45
+ []);
46
+ /**
47
+ * Правый месяц должен быть как минимум на 1 месяц больше левого
48
+ */
49
+ let initialMonthTo = useMemo(() => max([
50
+ selectedTo ? startOfMonth(selectedTo) : 0,
51
+ addMonths(initialMonthFrom, 1),
52
+ ]).getTime(),
53
+ // eslint-disable-next-line react-hooks/exhaustive-deps
54
+ []);
55
+ if (defaultMonthPosition === 'right') {
56
+ initialMonthTo = initialMonthFrom;
57
+ initialMonthFrom = subMonths(initialMonthFrom, 1).getTime();
58
+ }
59
+ const [monthFrom, setMonthFrom] = useState(initialMonthFrom);
60
+ const [monthTo, setMonthTo] = useState(initialMonthTo);
61
+ const handleMonthFromChange = useCallback((newMonthFrom) => {
62
+ setMonthFrom(newMonthFrom);
63
+ if (monthTo && isEqual(newMonthFrom, monthTo)) {
64
+ const nextMonth = addMonths(newMonthFrom, 1).getTime();
65
+ setMonthTo(nextMonth);
66
+ }
67
+ }, [monthTo]);
68
+ const handleMonthToChange = useCallback((newMonthTo) => {
69
+ setMonthTo(newMonthTo);
70
+ if (monthFrom && isEqual(newMonthTo, monthFrom)) {
71
+ const prevMonth = subMonths(newMonthTo, 1).getTime();
72
+ setMonthFrom(prevMonth);
73
+ }
74
+ }, [monthFrom]);
75
+ // eslint-disable-next-line complexity
76
+ useEffect(() => {
77
+ const selectedFromMonth = selectedFrom ? startOfMonth(selectedFrom).getTime() : undefined;
78
+ const selectedToMonth = selectedTo ? startOfMonth(selectedTo).getTime() : undefined;
79
+ // Проверяем, показываются ли выбранные месяцы в левой или правой части компонента
80
+ const fromMonthOnLeft = selectedFromMonth && selectedFromMonth === monthFrom;
81
+ const fromMonthOnRight = selectedFromMonth && selectedFromMonth === monthTo;
82
+ const toMonthOnRight = selectedToMonth && selectedToMonth === monthTo;
83
+ const toMonthOnLeft = selectedToMonth && selectedToMonth === monthFrom;
84
+ const fromMonthOnScreen = fromMonthOnLeft || fromMonthOnRight;
85
+ const toMonthOnScreen = toMonthOnLeft || toMonthOnRight;
86
+ if (fromMonthOnLeft && toMonthOnLeft) {
87
+ setMonthTo(max([addMonths(selectedFromMonth, 1), monthTo]).getTime());
88
+ return;
89
+ }
90
+ if (fromMonthOnRight && toMonthOnRight) {
91
+ setMonthFrom(min([subMonths(selectedToMonth, 1), monthFrom]).getTime());
92
+ return;
93
+ }
94
+ if (selectedFromMonth && selectedToMonth) {
95
+ setMonthFrom(selectedFromMonth);
96
+ setMonthTo(max([addMonths(selectedFromMonth, 1), selectedToMonth]).getTime());
97
+ return;
98
+ }
99
+ if (selectedFromMonth && !selectedToMonth && !fromMonthOnScreen) {
100
+ setMonthFrom(selectedFromMonth);
101
+ setMonthTo(max([addMonths(selectedFromMonth, 1), monthTo]).getTime());
102
+ }
103
+ if (selectedToMonth && !selectedFromMonth && !toMonthOnScreen) {
104
+ setMonthTo(selectedToMonth);
105
+ setMonthFrom(min([subMonths(selectedToMonth, 1), monthFrom]).getTime());
106
+ }
107
+ // eslint-disable-next-line react-hooks/exhaustive-deps
108
+ }, [selectedFrom, selectedTo]);
109
+ return {
110
+ monthFrom,
111
+ monthTo,
112
+ handleMonthFromChange,
113
+ handleMonthToChange,
114
+ };
115
+ }
116
+ function useSelectionProps(from, to, highlighted) {
117
+ return useMemo(() => {
118
+ if (from && to) {
119
+ return {
120
+ rangeComplete: true,
121
+ selectedFrom: min([from, to]).getTime(),
122
+ selectedTo: max([from, to]).getTime(),
123
+ };
124
+ }
125
+ const dates = [from, to, highlighted].filter((date) => date !== undefined);
126
+ return {
127
+ rangeComplete: false,
128
+ selectedFrom: from || dates.length === 2 ? min(dates).getTime() : undefined,
129
+ selectedTo: to || dates.length === 2 ? max(dates).getTime() : undefined,
130
+ };
131
+ }, [from, highlighted, to]);
132
+ }
133
+
134
+ export { usePopoverViewMonthes, useSelectionProps, useStaticViewMonthes };
@@ -0,0 +1 @@
1
+ export * from "./Component";
@@ -0,0 +1 @@
1
+ export { CalendarRange } from './Component.js';
@@ -0,0 +1,2 @@
1
+ declare const isDayButton: (node: HTMLElement | null) => string | false | null | undefined;
2
+ export { isDayButton };
@@ -0,0 +1,3 @@
1
+ const isDayButton = (node) => node && node.tagName === 'BUTTON' && node.dataset.date;
2
+
3
+ export { isDayButton };
@@ -0,0 +1,42 @@
1
+ /* */
2
+ :root {
3
+ --calendar-inner-width: 280px;
4
+
5
+ /* Кнопки выбора месяцев и годов */
6
+
7
+ /* Шапка */
8
+
9
+ /* День */
10
+
11
+ /* today */
12
+
13
+ /* highlighted */
14
+
15
+ /* holidays */
16
+
17
+ /* range */
18
+
19
+ /* selected */
20
+
21
+ /* disabled */
22
+
23
+ /* marker */
24
+ }
25
+ .component {
26
+ display: flex
27
+ }
28
+ .component button[aria-selected='true'] {
29
+ cursor: pointer;
30
+ }
31
+ .component *[class*='errorIcon_'] {
32
+ display: none;
33
+ }
34
+ .component *[class*='calendarIcon_'] {
35
+ margin-right: 0;
36
+ }
37
+ .static .calendar {
38
+ width: var(--calendar-inner-width)
39
+ }
40
+ .static .calendar > div:first-child {
41
+ padding: var(--gap-16) 0 var(--gap-12);
42
+ }
@@ -0,0 +1,5 @@
1
+ import { FC } from 'react';
2
+ import { CalendarRangeProps } from "../Component";
3
+ type CalendarRangePopoverProps = Omit<CalendarRangeProps, 'calendarPosition'>;
4
+ declare const CalendarRangePopover: FC<CalendarRangePopoverProps>;
5
+ export { CalendarRangePopoverProps, CalendarRangePopover };
@@ -0,0 +1,128 @@
1
+ import React, { useState, useCallback, useEffect } from 'react';
2
+ import cn from 'classnames';
3
+ import startOfMonth from 'date-fns/startOfMonth';
4
+ import { CalendarInput } from '@alfalab/core-components-calendar-input/moderncssm';
5
+ import { isValidInputValue, parseDateString } from '@alfalab/core-components-calendar-input/moderncssm/shared';
6
+ import { isCompleteDateInput } from '@alfalab/core-components-date-input/moderncssm';
7
+ import { useDidUpdateEffect } from '@alfalab/hooks';
8
+ import { Divider } from '../components/divider/Component.js';
9
+ import { usePopoverViewMonthes } from '../hooks.js';
10
+ import styles from './index.module.css';
11
+
12
+ const CalendarRangePopover = ({ className, defaultMonth = startOfMonth(new Date()).getTime(), minDate, maxDate, valueFrom = '', valueTo = '', onDateFromChange = () => null, onDateToChange = () => null, onChange = () => null, onError, inputFromProps = {}, inputToProps = {}, offDays, events, returnInvalidDates = false, dataTestId, }) => {
13
+ const [inputFromValue, setInputFromValue] = useState(valueFrom);
14
+ const [inputToValue, setInputToValue] = useState(valueTo);
15
+ /**
16
+ * Ключ для сброса календарей
17
+ * Пользователь открыл календарь, изменил месяц, но ничего не выбрал
18
+ * — при следующем открытии в календаре будет установлен начальный месяц
19
+ */
20
+ const [resetKey, setResetKey] = useState(0);
21
+ const dateFrom = isValidInputValue(inputFromValue, minDate, maxDate, offDays)
22
+ ? parseDateString(inputFromValue).getTime()
23
+ : null;
24
+ const dateTo = isValidInputValue(inputToValue, dateFrom || minDate, maxDate, offDays)
25
+ ? parseDateString(inputToValue).getTime()
26
+ : null;
27
+ const [inputFromInvalid, setInputFromInvalid] = useState(isCompleteDateInput(inputFromValue) && dateFrom === null);
28
+ const [inputToInvalid, setInputToInvalid] = useState(isCompleteDateInput(inputToValue) && dateTo === null);
29
+ const bothInvalid = isCompleteDateInput(inputFromValue) &&
30
+ isCompleteDateInput(inputToValue) &&
31
+ parseDateString(inputFromValue).getTime() > parseDateString(inputToValue).getTime();
32
+ const hasValidateError = inputFromInvalid || inputToInvalid || bothInvalid;
33
+ const { monthFrom, monthTo, handleMonthFromChange, handleMonthToChange } = usePopoverViewMonthes({
34
+ dateFrom,
35
+ dateTo,
36
+ defaultMonth,
37
+ resetKey,
38
+ });
39
+ const handleValidInputFrom = useCallback(() => {
40
+ setInputFromInvalid(inputFromValue !== '' && !isValidInputValue(inputFromValue, minDate, maxDate, offDays));
41
+ }, [inputFromValue, maxDate, minDate, offDays]);
42
+ const handleValidInputTo = useCallback(() => {
43
+ setInputToInvalid(inputToValue !== '' &&
44
+ !isValidInputValue(inputToValue, dateFrom || minDate, maxDate, offDays));
45
+ }, [dateFrom, inputToValue, maxDate, minDate, offDays]);
46
+ const handleInputFromChange = (event, payload) => {
47
+ setInputFromValue(payload.value);
48
+ inputFromProps.onInputChange?.(event, payload);
49
+ };
50
+ const handleInputToChange = (event, payload) => {
51
+ setInputToValue(payload.value);
52
+ inputToProps.onInputChange?.(event, payload);
53
+ };
54
+ const handleInputFromBlur = useCallback(() => {
55
+ handleValidInputFrom();
56
+ setResetKey(+new Date());
57
+ }, [handleValidInputFrom]);
58
+ const handleInputToBlur = useCallback(() => {
59
+ handleValidInputTo();
60
+ setResetKey(+new Date());
61
+ }, [handleValidInputTo]);
62
+ const handleFromChange = useCallback((_, payload) => {
63
+ setInputFromValue(payload.value);
64
+ }, []);
65
+ const handleToChange = useCallback((_, payload) => {
66
+ setInputToValue(payload.value);
67
+ }, []);
68
+ useEffect(() => {
69
+ setInputFromValue(valueFrom);
70
+ }, [valueFrom]);
71
+ useEffect(() => {
72
+ setInputToValue(valueTo);
73
+ }, [valueTo]);
74
+ useDidUpdateEffect(() => {
75
+ onDateFromChange({ value: inputFromValue, date: dateFrom });
76
+ onChange({
77
+ valueFrom: inputFromValue,
78
+ valueTo: inputToValue,
79
+ dateFrom,
80
+ dateTo,
81
+ });
82
+ if (!inputFromValue || isCompleteDateInput(inputFromValue)) {
83
+ handleValidInputFrom();
84
+ }
85
+ // eslint-disable-next-line react-hooks/exhaustive-deps
86
+ }, [inputFromValue]);
87
+ useDidUpdateEffect(() => {
88
+ onDateToChange({ value: inputToValue, date: dateTo });
89
+ // eslint-disable-next-line no-nested-ternary
90
+ const inputDateTo = returnInvalidDates
91
+ ? isCompleteDateInput(inputToValue)
92
+ ? parseDateString(inputToValue).getTime()
93
+ : null
94
+ : dateTo;
95
+ onChange({
96
+ valueFrom: inputFromValue,
97
+ valueTo: inputToValue,
98
+ dateFrom,
99
+ dateTo: inputDateTo,
100
+ });
101
+ if (!inputToValue || isCompleteDateInput(inputToValue)) {
102
+ handleValidInputTo();
103
+ }
104
+ // eslint-disable-next-line react-hooks/exhaustive-deps
105
+ }, [inputToValue]);
106
+ useEffect(() => {
107
+ if (onError) {
108
+ onError(hasValidateError);
109
+ }
110
+ // eslint-disable-next-line react-hooks/exhaustive-deps
111
+ }, [hasValidateError]);
112
+ return (React.createElement("div", { className: cn(styles.component, className), "data-test-id": dataTestId },
113
+ React.createElement(CalendarInput, { ...inputFromProps, useAnchorWidth: false, calendarPosition: 'popover', popoverPosition: 'bottom-start', error: inputFromInvalid || bothInvalid || inputFromProps.error, onChange: handleFromChange, onInputChange: handleInputFromChange, onBlur: handleInputFromBlur, value: inputFromValue, minDate: minDate, maxDate: maxDate, offDays: offDays, events: events, calendarProps: {
114
+ ...inputFromProps.calendarProps,
115
+ month: monthFrom,
116
+ onMonthChange: handleMonthFromChange,
117
+ selectorView: 'full',
118
+ } }),
119
+ React.createElement(Divider, { inputFromProps: inputFromProps, inputToProps: inputToProps }),
120
+ React.createElement(CalendarInput, { ...inputToProps, useAnchorWidth: false, calendarPosition: 'popover', popoverPosition: 'bottom-end', error: inputToInvalid || bothInvalid || inputToProps.error, onChange: handleToChange, onInputChange: handleInputToChange, onBlur: handleInputToBlur, value: inputToValue, minDate: dateFrom || minDate, maxDate: maxDate, offDays: offDays, events: events, calendarProps: {
121
+ ...inputToProps.calendarProps,
122
+ month: monthTo,
123
+ onMonthChange: handleMonthToChange,
124
+ selectorView: 'full',
125
+ } })));
126
+ };
127
+
128
+ export { CalendarRangePopover };
@@ -0,0 +1,10 @@
1
+ import { FC } from 'react';
2
+ import { CalendarRangeProps } from "../Component";
3
+ type CalendarRangeStaticProps = Omit<CalendarRangeProps, 'calendarPosition'> & {
4
+ /**
5
+ * Отображать начальный месяц слева или справа (влияет только на начальный рендер)
6
+ */
7
+ defaultMonthPosition?: 'left' | 'right';
8
+ };
9
+ declare const CalendarRangeStatic: FC<CalendarRangeStaticProps>;
10
+ export { CalendarRangeStaticProps, CalendarRangeStatic };
@@ -0,0 +1,176 @@
1
+ import React, { useState, useCallback, useEffect } from 'react';
2
+ import cn from 'classnames';
3
+ import addMonths from 'date-fns/addMonths';
4
+ import endOfMonth from 'date-fns/endOfMonth';
5
+ import isSameMonth from 'date-fns/isSameMonth';
6
+ import max from 'date-fns/max';
7
+ import startOfMonth from 'date-fns/startOfMonth';
8
+ import subMonths from 'date-fns/subMonths';
9
+ import { CalendarDesktop } from '@alfalab/core-components-calendar/moderncssm/desktop';
10
+ import { usePeriodWithReset } from '@alfalab/core-components-calendar/moderncssm/shared';
11
+ import { isValidInputValue, parseDateString, formatDate } from '@alfalab/core-components-calendar-input/moderncssm/shared';
12
+ import { isCompleteDateInput, DateInput } from '@alfalab/core-components-date-input/moderncssm';
13
+ import { Divider } from '../components/divider/Component.js';
14
+ import { useStaticViewMonthes, useSelectionProps } from '../hooks.js';
15
+ import { isDayButton } from '../utils.js';
16
+ import styles from './index.module.css';
17
+
18
+ /* eslint-disable complexity */
19
+ const CalendarRangeStatic = ({ className, defaultMonth = startOfMonth(new Date()).getTime(), defaultMonthPosition = 'left', minDate, maxDate, valueFrom = '', valueTo = '', onDateFromChange = () => null, onDateToChange = () => null, onChange = () => null, onError, inputFromProps = {}, inputToProps = {}, offDays, events, returnInvalidDates = false, dataTestId, }) => {
20
+ const [inputFromValue, setInputFromValue] = useState(valueFrom);
21
+ const [inputToValue, setInputToValue] = useState(valueTo);
22
+ let dateFrom = isValidInputValue(inputFromValue, minDate, maxDate, offDays)
23
+ ? parseDateString(inputFromValue).getTime()
24
+ : null;
25
+ const dateTo = isValidInputValue(inputToValue, dateFrom || minDate, maxDate, offDays)
26
+ ? parseDateString(inputToValue).getTime()
27
+ : null;
28
+ if (isCompleteDateInput(inputToValue) && !dateTo && !returnInvalidDates) {
29
+ dateFrom = null;
30
+ }
31
+ const bothInvalid = isCompleteDateInput(inputFromValue) &&
32
+ isCompleteDateInput(inputToValue) &&
33
+ parseDateString(inputFromValue).getTime() > parseDateString(inputToValue).getTime();
34
+ const [highlightedDate, setHighlightedDate] = useState(undefined);
35
+ const period = usePeriodWithReset({
36
+ initialSelectedFrom: dateFrom ? parseDateString(inputFromValue).getTime() : undefined,
37
+ initialSelectedTo: dateTo ? parseDateString(inputToValue).getTime() : undefined,
38
+ });
39
+ const validateInputFromValue = useCallback((value) => isValidInputValue(value, minDate, dateFrom || maxDate, offDays), [dateFrom, maxDate, minDate, offDays]);
40
+ const validateInputToValue = useCallback((value) => isValidInputValue(value, dateFrom || minDate, maxDate, offDays), [dateFrom, minDate, maxDate, offDays]);
41
+ const [inputFromInvalid, setInputFromInvalid] = useState(isCompleteDateInput(inputFromValue) && dateFrom === null);
42
+ const [inputToInvalid, setInputToInvalid] = useState(isCompleteDateInput(inputToValue) && dateTo === null);
43
+ const hasValidateError = bothInvalid || inputFromInvalid || inputToInvalid;
44
+ const { calendarProps: calendarFromProps, onInputChange: onInputChangeFrom, ...dateInputFromProps } = inputFromProps;
45
+ const { calendarProps: calendarToProps, onInputChange: onInputChangeTo, ...dateInputToProps } = inputToProps;
46
+ const { monthFrom, monthTo, handleMonthFromChange, handleMonthToChange } = useStaticViewMonthes({
47
+ selectedFrom: period.selectedFrom,
48
+ selectedTo: period.selectedTo,
49
+ defaultMonth,
50
+ defaultMonthPosition,
51
+ });
52
+ const handleValidInputFrom = useCallback(() => {
53
+ setInputFromInvalid(inputFromValue !== '' && !validateInputFromValue(inputFromValue));
54
+ }, [inputFromValue, validateInputFromValue]);
55
+ const handleValidInputTo = useCallback(() => {
56
+ setInputToInvalid(inputToValue !== '' && !validateInputToValue(inputToValue));
57
+ }, [inputToValue, validateInputToValue]);
58
+ const handleInputFromChange = (event, payload) => {
59
+ setInputFromValue(payload.value);
60
+ onInputChangeFrom?.(event, payload);
61
+ };
62
+ const handleInputToChange = (event, payload) => {
63
+ setInputToValue(payload.value);
64
+ onInputChangeTo?.(event, payload);
65
+ };
66
+ const handleMouseOver = useCallback((event) => {
67
+ const target = event.target;
68
+ const mouseOverDayButton = isDayButton(target) || isDayButton(target.parentElement);
69
+ let date;
70
+ if (mouseOverDayButton) {
71
+ const button = target.tagName === 'BUTTON' ? target : target.parentElement;
72
+ if (button.dataset.date) {
73
+ date = +button.dataset.date;
74
+ }
75
+ }
76
+ setHighlightedDate(date);
77
+ }, []);
78
+ const handleClearFrom = useCallback(() => {
79
+ setInputFromValue('');
80
+ }, []);
81
+ const handleClearTo = useCallback(() => {
82
+ setInputToValue('');
83
+ }, []);
84
+ useEffect(() => {
85
+ setInputFromValue(period.selectedFrom ? formatDate(period.selectedFrom) : '');
86
+ }, [period.selectedFrom]);
87
+ useEffect(() => {
88
+ setInputToValue(period.selectedTo ? formatDate(period.selectedTo) : '');
89
+ }, [period.selectedTo]);
90
+ useEffect(() => {
91
+ setInputFromValue(valueFrom);
92
+ }, [valueFrom]);
93
+ useEffect(() => {
94
+ setInputToValue(valueTo);
95
+ }, [valueTo]);
96
+ useEffect(() => {
97
+ if (!inputFromValue || isCompleteDateInput(inputFromValue)) {
98
+ handleValidInputFrom();
99
+ }
100
+ period.setStart(dateFrom || undefined);
101
+ if (dateTo) {
102
+ period.setEnd(dateTo);
103
+ }
104
+ if (inputFromValue !== valueFrom) {
105
+ onDateFromChange({
106
+ value: inputFromValue,
107
+ date: dateFrom,
108
+ });
109
+ onChange({
110
+ valueFrom: inputFromValue,
111
+ valueTo: inputToValue,
112
+ dateFrom,
113
+ dateTo,
114
+ });
115
+ }
116
+ // eslint-disable-next-line react-hooks/exhaustive-deps
117
+ }, [inputFromValue]);
118
+ useEffect(() => {
119
+ if (!inputToValue || isCompleteDateInput(inputToValue)) {
120
+ handleValidInputTo();
121
+ }
122
+ period.setEnd(dateTo || undefined);
123
+ if (dateFrom) {
124
+ period.setStart(dateFrom);
125
+ }
126
+ if (inputToValue !== valueTo) {
127
+ // eslint-disable-next-line no-nested-ternary
128
+ const inputDateTo = returnInvalidDates
129
+ ? isCompleteDateInput(inputToValue)
130
+ ? parseDateString(inputToValue).getTime()
131
+ : null
132
+ : dateTo;
133
+ onDateToChange({
134
+ value: inputToValue,
135
+ date: inputDateTo,
136
+ });
137
+ onChange({
138
+ valueFrom: inputFromValue,
139
+ valueTo: inputToValue,
140
+ dateFrom,
141
+ dateTo: inputDateTo,
142
+ });
143
+ }
144
+ // eslint-disable-next-line react-hooks/exhaustive-deps
145
+ }, [inputToValue]);
146
+ useEffect(() => {
147
+ if (onError) {
148
+ onError(hasValidateError);
149
+ }
150
+ // eslint-disable-next-line react-hooks/exhaustive-deps
151
+ }, [hasValidateError]);
152
+ const rangeProps = useSelectionProps(period.selectedFrom, period.selectedTo, highlightedDate);
153
+ const CalendarFromComponent = dateInputFromProps.Calendar || CalendarDesktop;
154
+ const CalendarToComponent = dateInputToProps.Calendar || CalendarDesktop;
155
+ const minMaxInSameMonth = minDate && maxDate && isSameMonth(minDate, maxDate);
156
+ return (
157
+ // eslint-disable-next-line jsx-a11y/mouse-events-have-key-events
158
+ React.createElement("div", { className: cn(styles.component, styles.static, className), onMouseOver: handleMouseOver, "data-test-id": dataTestId },
159
+ React.createElement("div", null,
160
+ React.createElement(DateInput, { ...dateInputFromProps, mobileMode: dateInputFromProps.mobileMode === 'popover'
161
+ ? 'input'
162
+ : dateInputFromProps.mobileMode, value: inputFromValue, onChange: handleInputFromChange, onClear: handleClearFrom, onBlur: handleValidInputFrom, error: bothInvalid || inputFromInvalid || dateInputFromProps.error, clear: true, block: true }),
163
+ React.createElement(CalendarFromComponent, { ...calendarFromProps, className: cn(styles.calendar, calendarFromProps?.className), month: monthFrom, selectorView: 'month-only', offDays: offDays, events: events, onChange: period.updatePeriod, onMonthChange: handleMonthFromChange, minDate: minDate, maxDate: minMaxInSameMonth
164
+ ? maxDate
165
+ : maxDate && max([maxDate, endOfMonth(subMonths(maxDate, 1))]).getTime(), ...rangeProps })),
166
+ React.createElement(Divider, { inputFromProps: inputFromProps, inputToProps: inputToProps }),
167
+ React.createElement("div", null,
168
+ React.createElement(DateInput, { ...dateInputToProps, mobileMode: dateInputToProps.mobileMode === 'popover'
169
+ ? 'input'
170
+ : dateInputToProps.mobileMode, value: inputToValue, onChange: handleInputToChange, onClear: handleClearTo, onBlur: handleValidInputTo, error: bothInvalid || inputToInvalid || dateInputToProps.error, clear: true, block: true }),
171
+ React.createElement(CalendarToComponent, { ...calendarToProps, className: cn(styles.calendar, calendarToProps?.className), month: monthTo, selectorView: 'month-only', offDays: offDays, events: events, onChange: period.updatePeriod, onMonthChange: handleMonthToChange, minDate: minMaxInSameMonth
172
+ ? minDate
173
+ : minDate && startOfMonth(addMonths(minDate, 1)).getTime(), maxDate: maxDate, ...rangeProps }))));
174
+ };
175
+
176
+ export { CalendarRangeStatic };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alfalab/core-components-calendar-range",
3
- "version": "7.3.28",
3
+ "version": "7.4.0",
4
4
  "description": "Calendar range component",
5
5
  "keywords": [],
6
6
  "license": "MIT",
@@ -15,14 +15,14 @@
15
15
  "react-dom": "^16.9.0 || ^17.0.1 || ^18.0.0"
16
16
  },
17
17
  "dependencies": {
18
- "@alfalab/core-components-calendar": "^7.10.1",
19
- "@alfalab/core-components-calendar-input": "^10.2.26",
20
- "@alfalab/core-components-date-input": "^4.3.37",
18
+ "@alfalab/core-components-calendar": "^7.11.0",
19
+ "@alfalab/core-components-calendar-input": "^10.3.0",
20
+ "@alfalab/core-components-date-input": "^4.4.0",
21
21
  "@alfalab/hooks": "^1.13.0",
22
22
  "classnames": "^2.3.1",
23
23
  "date-fns": "^2.16.1",
24
24
  "tslib": "^2.4.0"
25
25
  },
26
- "themesVersion": "13.0.2",
27
- "varsVersion": "9.11.1"
26
+ "themesVersion": "13.1.0",
27
+ "varsVersion": "9.12.0"
28
28
  }
@@ -1,4 +1,4 @@
1
- @import '@alfalab/core-components-themes/src/default.css';
1
+ @import '@alfalab/core-components-vars/src/index.css';
2
2
  @import '@alfalab/core-components-calendar/src/vars.css';
3
3
 
4
4
  .component {
@@ -1,4 +1,4 @@
1
- @import '@alfalab/core-components-themes/src/default.css';
1
+ @import '@alfalab/core-components-vars/src/index.css';
2
2
  @import '@alfalab/core-components-calendar/src/vars.css';
3
3
 
4
4
  .component {