@true-engineering/true-react-common-ui-kit 3.20.0 → 3.21.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 (90) hide show
  1. package/LICENSE +201 -201
  2. package/README.md +12 -0
  3. package/dist/components/DatePicker/types.d.ts +1 -1
  4. package/dist/components/WithPopup/WithPopup.d.ts +1 -1
  5. package/dist/true-react-common-ui-kit.js +61 -61
  6. package/dist/true-react-common-ui-kit.js.map +1 -1
  7. package/dist/true-react-common-ui-kit.umd.cjs +61 -61
  8. package/dist/true-react-common-ui-kit.umd.cjs.map +1 -1
  9. package/package.json +1 -1
  10. package/src/components/AccountInfo/AccountInfo.stories.tsx +32 -32
  11. package/src/components/AccountInfo/AccountInfo.tsx +80 -80
  12. package/src/components/AddButton/AddButton.stories.tsx +21 -21
  13. package/src/components/AddButton/AddButton.tsx +52 -52
  14. package/src/components/Button/Button.tsx +129 -129
  15. package/src/components/Colors/Colors.stories.tsx +7 -7
  16. package/src/components/DateInput/DateInput.tsx +90 -90
  17. package/src/components/DateInput/constants.ts +2 -2
  18. package/src/components/DatePicker/DatePicker.tsx +310 -308
  19. package/src/components/DatePicker/types.ts +1 -0
  20. package/src/components/Description/Description.stories.tsx +27 -27
  21. package/src/components/Description/Description.tsx +61 -61
  22. package/src/components/FiltersPane/components/FilterValueView/FilterValueView.tsx +166 -166
  23. package/src/components/FiltersPane/components/FilterWithDates/FilterWithDates.tsx +210 -210
  24. package/src/components/FiltersPane/components/FilterWithPeriod/FilterWithPeriod.tsx +177 -177
  25. package/src/components/Flag/Flag.stories.tsx +29 -29
  26. package/src/components/Flag/Flag.tsx +26 -26
  27. package/src/components/Flag/augment.d.ts +1 -1
  28. package/src/components/FlexibleTable/components/FlexibleTableCell/FlexibleTableCell.styles.ts +38 -38
  29. package/src/components/FlexibleTable/components/FlexibleTableRow/FlexibleTableRow.styles.ts +25 -25
  30. package/src/components/FlexibleTable/components/FlexibleTableRow/FlexibleTableRow.tsx +196 -196
  31. package/src/components/FlexibleTable/helpers.ts +13 -13
  32. package/src/components/Icon/Icon.stories.tsx +86 -86
  33. package/src/components/Icon/complexIcons/augment.d.ts +1 -1
  34. package/src/components/Icon/complexIcons/avatarGreen.svg +57 -57
  35. package/src/components/Icon/complexIcons/index.ts +1 -1
  36. package/src/components/IncrementInput/IncrementInput.tsx +105 -105
  37. package/src/components/Input/Input.tsx +297 -297
  38. package/src/components/Input/types.ts +32 -32
  39. package/src/components/List/List.stories.tsx +70 -70
  40. package/src/components/List/List.tsx +33 -33
  41. package/src/components/List/components/ListItem/ListItem.tsx +57 -57
  42. package/src/components/Modal/Modal.stories.tsx +105 -105
  43. package/src/components/MultiSelect/MultiSelect.stories.tsx +46 -46
  44. package/src/components/MultiSelect/MultiSelect.tsx +106 -106
  45. package/src/components/MultiSelect/components/MultiSelectInput/MultiSelectInput.tsx +53 -53
  46. package/src/components/Notification/Notification.stories.tsx +46 -46
  47. package/src/components/Notification/Notification.tsx +69 -69
  48. package/src/components/NumberInput/NumberInput.tsx +137 -137
  49. package/src/components/NumberInput/index.ts +1 -1
  50. package/src/components/PhoneInput/PhoneInput.tsx +214 -214
  51. package/src/components/PhoneInput/components/PhoneInputCountryList/PhoneInputCountryList.tsx +155 -155
  52. package/src/components/PhoneInput/types.ts +16 -16
  53. package/src/components/RadioButton/RadioButton.stories.tsx +46 -46
  54. package/src/components/RadioButton/RadioButton.tsx +57 -57
  55. package/src/components/ScrollIntoViewIfNeeded/index.ts +1 -1
  56. package/src/components/Select/MultiSelect.stories.tsx +240 -240
  57. package/src/components/Select/Select.stories.tsx +235 -235
  58. package/src/components/Select/constants.ts +2 -2
  59. package/src/components/Select/types.ts +1 -1
  60. package/src/components/Selector/Selector.stories.tsx +62 -62
  61. package/src/components/Selector/Selector.tsx +115 -115
  62. package/src/components/Selector/index.ts +2 -2
  63. package/src/components/Selector/types.ts +12 -12
  64. package/src/components/Skeleton/Skeleton.stories.tsx +19 -19
  65. package/src/components/SmartInput/SmartInput.tsx +134 -134
  66. package/src/components/Status/Status.stories.tsx +73 -73
  67. package/src/components/Status/Status.styles.ts +143 -143
  68. package/src/components/Status/Status.tsx +49 -49
  69. package/src/components/Status/constants.ts +11 -11
  70. package/src/components/Status/index.ts +3 -3
  71. package/src/components/Status/types.ts +5 -5
  72. package/src/components/Switch/Switch.stories.tsx +40 -40
  73. package/src/components/Switch/Switch.tsx +75 -75
  74. package/src/components/TextArea/TextArea.styles.ts +1 -3
  75. package/src/components/TextWithInfo/TextWithInfo.stories.tsx +53 -53
  76. package/src/components/TextWithInfo/TextWithInfo.tsx +62 -62
  77. package/src/components/TextWithTooltip/TextWithTooltip.stories.tsx +58 -58
  78. package/src/components/ThemedPreloader/ThemedPreloader.stories.tsx +41 -41
  79. package/src/components/ThemedPreloader/ThemedPreloader.tsx +54 -54
  80. package/src/components/ThemedPreloader/components/DefaultPreloader/index.ts +1 -1
  81. package/src/components/Toaster/Toaster.stories.tsx +30 -30
  82. package/src/components/Tooltip/Tooltip.stories.tsx +19 -19
  83. package/src/components/Tooltip/Tooltip.tsx +35 -35
  84. package/src/components/Tooltip/types.ts +1 -1
  85. package/src/components/WithPopup/WithPopup.tsx +1 -1
  86. package/src/helpers/popper-helpers.ts +17 -17
  87. package/src/hooks/use-dropdown.ts +84 -84
  88. package/src/hooks/use-is-mounted.ts +15 -15
  89. package/src/theme/helpers.ts +76 -76
  90. package/src/vite-env.d.ts +1 -1
@@ -1,308 +1,310 @@
1
- import { useState, useEffect, FC, FocusEvent, SyntheticEvent, forwardRef, useMemo } from 'react';
2
- import ReactDatePicker from 'react-datepicker';
3
- import 'react-datepicker/dist/react-datepicker.css';
4
- import clsx from 'clsx';
5
- import { isAfter, isBefore, isValid } from 'date-fns';
6
- import {
7
- isEmpty,
8
- isNotEmpty,
9
- isStringNotEmpty,
10
- } from '@true-engineering/true-react-platform-helpers';
11
- import { addDataAttributes } from '../../helpers';
12
- import { useTweakStyles } from '../../hooks';
13
- import { ICommonProps } from '../../types';
14
- import { DateInput, EMPTY_DATE_INPUT_VALUE, IDateInputProps } from '../DateInput';
15
- import { DatePickerHeader, PopperContainer } from './components';
16
- import { DatePickerComponent, DEFAULT_DATE_FORMAT } from './constants';
17
- import { areDatesEquals, getDateFormatter, getDateValueParser } from './helpers';
18
- import { IDatePickerBaseProps, IRange } from './types';
19
- import { useStyles, IDatePickerStyles } from './DatePicker.styles';
20
-
21
- export interface IDatePickerProps extends IDatePickerBaseProps, ICommonProps<IDatePickerStyles> {
22
- selectedDate?: Date | null;
23
- locale: Locale;
24
- months?: string[];
25
- /** @default 'dd.MM.yyyy' */
26
- dateFormat?: string;
27
- /** @default 1 */
28
- calendarStartDay?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
29
- /** @default false */
30
- isRange?: boolean;
31
- /** @default false */
32
- isInline?: boolean;
33
- /** @default false */
34
- shouldRenderPopperInBody?: boolean;
35
- customInput?: FC<IDateInputProps>;
36
- onChangeDate?: (date: Date | null, event?: SyntheticEvent) => void;
37
- onChangeRange?: (date: IRange, event?: SyntheticEvent) => void;
38
- }
39
-
40
- export const DatePicker = forwardRef<ReactDatePicker, IDatePickerProps>(
41
- (
42
- {
43
- data,
44
- selectedDate = null,
45
- minDate,
46
- maxDate,
47
- endDate = null,
48
- startDate = null,
49
- locale,
50
- months,
51
- calendarStartDay = 1,
52
- dateFormat = DEFAULT_DATE_FORMAT,
53
- monthsShown,
54
- placeholder,
55
- isRange = false,
56
- isInline = false,
57
- isDisabled,
58
- isClearable,
59
- strictParsing,
60
- focusSelectedMonth,
61
- disabledKeyboardNavigation,
62
- shouldRenderPopperInBody = false,
63
- allowSameDay = false,
64
- shouldCloseOnSelect,
65
- showPreviousMonths,
66
- preventOpenOnFocus,
67
- popperModifiers,
68
- popperPlacement,
69
- todayButton,
70
- calendarContainer,
71
- dayClassName,
72
- customInput: CustomInput = DateInput,
73
- customInputRef,
74
- renderCustomHeader,
75
- filterDate,
76
- onYearChange,
77
- onMonthChange,
78
- onCalendarOpen,
79
- onCalendarClose,
80
- onChangeDate,
81
- onChangeRange,
82
- onBlur,
83
- onFocus,
84
- onKeyDown,
85
- tweakStyles,
86
- ...inputProps
87
- },
88
- ref,
89
- ) => {
90
- const classes = useStyles({ theme: tweakStyles });
91
-
92
- const tweakDateInputStyles = useTweakStyles({
93
- tweakStyles,
94
- className: 'tweakDateInput',
95
- currentComponentName: 'DatePicker',
96
- });
97
-
98
- const { formatDate, parseDateValue } = useMemo(
99
- () => ({
100
- formatDate: getDateFormatter(dateFormat),
101
- parseDateValue: getDateValueParser(dateFormat),
102
- }),
103
- [dateFormat],
104
- );
105
-
106
- const [isOpen, setIsOpen] = useState(false);
107
-
108
- const [dateValue, setDateValue] = useState(formatDate(selectedDate));
109
-
110
- const [start, setStart] = useState(startDate);
111
- const [startDateValue, setStartDateValue] = useState(formatDate(startDate));
112
- const [end, setEnd] = useState(endDate);
113
- const [endDateValue, setEndDateValue] = useState(formatDate(endDate));
114
-
115
- const hasDateInputValue = isRange
116
- ? isStringNotEmpty(startDateValue) || isStringNotEmpty(endDateValue)
117
- : isStringNotEmpty(dateValue);
118
-
119
- const dateInputProps: IDateInputProps = {
120
- ...inputProps,
121
- isRange,
122
- isDisabled,
123
- isClearable,
124
- isActive: isOpen,
125
- iconType: isClearable && hasDateInputValue ? undefined : 'calendar',
126
- tweakStyles: tweakDateInputStyles,
127
- ...(isRange ? { startDate: startDateValue, endDate: endDateValue } : { date: dateValue }),
128
- };
129
-
130
- const handleChangeDate = (value: Date | null, event?: SyntheticEvent) => {
131
- onChangeDate?.(value, event);
132
- };
133
-
134
- const isDateInRange = (date: Date) =>
135
- (isEmpty(minDate) || isAfter(date, minDate)) && (isEmpty(maxDate) || isBefore(date, maxDate));
136
-
137
- // TODO: Если пропса allowSameDay равна true и введена только начальная дата, то
138
- // невозможно будет стереть значение в инпуте. Обойти это можно только если
139
- // полностью выбрать период, а затем уже очищать инпут (баг в react-datepicker. В этом
140
- // случае value равняется не [null, null], а [start, null])
141
- const handleChangeRange = (value: IRange, event?: SyntheticEvent) => {
142
- if (
143
- allowSameDay ||
144
- !areDatesEquals(value?.[0], startDate) ||
145
- !areDatesEquals(value?.[1], endDate)
146
- ) {
147
- setStart(value?.[0] ?? null);
148
- setEnd(value?.[1] ?? null);
149
- onChangeRange?.(value, event);
150
- }
151
- };
152
-
153
- const handleChangeDateRangeInput = (value: string) => {
154
- const newStartDateValue = value.slice(0, 10);
155
- let newStart = parseDateValue(newStartDateValue);
156
- const newEndDateValue = value.slice(13);
157
- let newEnd = parseDateValue(newEndDateValue);
158
-
159
- if (
160
- (isNotEmpty(newStart) && !isValid(newStart)) ||
161
- (isNotEmpty(newStart) && !isDateInRange(newStart))
162
- ) {
163
- newStart = start;
164
- }
165
-
166
- if (
167
- (isNotEmpty(newEnd) && !isValid(newEnd)) ||
168
- (isNotEmpty(newEnd) && !isDateInRange(newEnd))
169
- ) {
170
- newEnd = end;
171
- }
172
-
173
- // Если оставить пустой начальную дату и заполненной конечную,
174
- // то ломается react-datepicker и в календарике ничего нельзя выбирать
175
- if (
176
- (isEmpty(newStart) && isValid(newEnd)) ||
177
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
178
- (isValid(newStart) && isValid(newEnd) && isAfter(newStart!, newEnd!))
179
- ) {
180
- newStart = newEnd;
181
- newEnd = null;
182
- }
183
-
184
- setStartDateValue(newStartDateValue);
185
- setStart(newStart);
186
- setEndDateValue(newEndDateValue);
187
- setEnd(newEnd);
188
- };
189
-
190
- const handleDateInputBlur = (event: FocusEvent<HTMLInputElement>) => {
191
- onBlur?.(event);
192
- setDateValue(formatDate(selectedDate));
193
- };
194
-
195
- const setDateRangeValues = (startValue: Date | null = null, endValue: Date | null = null) => {
196
- let convertedStartDate = formatDate(startValue);
197
- const convertedEndDate = formatDate(endValue);
198
- if (convertedStartDate === '' && convertedEndDate !== '') {
199
- // Если выставлять пустую строку, то конечная дата перепрыгивает на место начальной
200
- convertedStartDate = EMPTY_DATE_INPUT_VALUE;
201
- }
202
-
203
- setStart(startValue);
204
- setStartDateValue(convertedStartDate);
205
- setEnd(endValue);
206
- setEndDateValue(convertedEndDate);
207
- };
208
-
209
- const handleDateRangeInputBlur = (event: FocusEvent<HTMLInputElement>) => {
210
- onBlur?.(event);
211
- handleChangeRange([start, end], event);
212
- setDateRangeValues(start, end);
213
- };
214
-
215
- const handleOpenCalendar = () => {
216
- setIsOpen(true);
217
- onCalendarOpen?.();
218
- };
219
-
220
- const handleCloseCalendar = () => {
221
- setIsOpen(false);
222
- if (isRange) {
223
- handleChangeRange([start, end]);
224
- setDateRangeValues(start, end);
225
- } else {
226
- setDateValue(formatDate(selectedDate));
227
- }
228
- onCalendarClose?.();
229
- };
230
-
231
- useEffect(() => {
232
- setDateValue(formatDate(selectedDate));
233
- setDateRangeValues(startDate, endDate);
234
- }, [selectedDate, startDate, endDate]);
235
-
236
- return (
237
- <div className={classes.root} {...addDataAttributes(data)}>
238
- <DatePickerComponent
239
- ref={ref}
240
- minDate={minDate}
241
- maxDate={maxDate}
242
- locale={locale}
243
- dateFormat={dateFormat}
244
- placeholderText={placeholder}
245
- calendarStartDay={calendarStartDay}
246
- inline={isInline}
247
- disabled={isDisabled}
248
- showPreviousMonths={showPreviousMonths}
249
- focusSelectedMonth={focusSelectedMonth}
250
- monthsShown={monthsShown}
251
- allowSameDay={allowSameDay}
252
- showPopperArrow={false}
253
- popperClassName={classes.popper}
254
- calendarClassName={classes.datepicker}
255
- dayClassName={(v) => clsx(classes.day, dayClassName?.(v))}
256
- disabledKeyboardNavigation={disabledKeyboardNavigation}
257
- popperContainer={shouldRenderPopperInBody ? PopperContainer : undefined}
258
- popperModifiers={popperModifiers}
259
- popperPlacement={popperPlacement}
260
- selectsRange={isRange}
261
- strictParsing={strictParsing}
262
- preventOpenOnFocus={preventOpenOnFocus}
263
- shouldCloseOnSelect={shouldCloseOnSelect}
264
- customInputRef={customInputRef}
265
- customInput={<CustomInput {...dateInputProps} />}
266
- renderCustomHeader={
267
- renderCustomHeader ??
268
- ((baseProps) => <DatePickerHeader {...baseProps} months={months} />)
269
- }
270
- todayButton={todayButton}
271
- calendarContainer={calendarContainer}
272
- filterDate={filterDate}
273
- onYearChange={onYearChange}
274
- onMonthChange={onMonthChange}
275
- onFocus={onFocus}
276
- onKeyDown={onKeyDown}
277
- onCalendarOpen={handleOpenCalendar}
278
- onCalendarClose={handleCloseCalendar}
279
- onChangeRaw={(_, value?: string) => {
280
- // Если передали value, значит этот обработчик вызвался после изменения значения в инпуте
281
- // (react-datepicker вызывает эту функцию также при клике на дату в календаре)
282
- if (value === undefined) {
283
- return;
284
- }
285
- if (isRange) {
286
- handleChangeDateRangeInput(value);
287
- } else {
288
- setDateValue(value);
289
- }
290
- }}
291
- {...(isRange
292
- ? {
293
- startDate: start,
294
- endDate: end,
295
- selected: start,
296
- onBlur: handleDateRangeInputBlur,
297
- onChange: handleChangeRange,
298
- }
299
- : {
300
- selected: selectedDate,
301
- onBlur: handleDateInputBlur,
302
- onChange: handleChangeDate,
303
- })}
304
- />
305
- </div>
306
- );
307
- },
308
- );
1
+ import { useState, useEffect, FC, FocusEvent, SyntheticEvent, forwardRef, useMemo } from 'react';
2
+ import ReactDatePicker from 'react-datepicker';
3
+ import 'react-datepicker/dist/react-datepicker.css';
4
+ import clsx from 'clsx';
5
+ import { isAfter, isBefore, isValid } from 'date-fns';
6
+ import {
7
+ isEmpty,
8
+ isNotEmpty,
9
+ isStringNotEmpty,
10
+ } from '@true-engineering/true-react-platform-helpers';
11
+ import { addDataAttributes } from '../../helpers';
12
+ import { useTweakStyles } from '../../hooks';
13
+ import { ICommonProps } from '../../types';
14
+ import { DateInput, EMPTY_DATE_INPUT_VALUE, IDateInputProps } from '../DateInput';
15
+ import { DatePickerHeader, PopperContainer } from './components';
16
+ import { DatePickerComponent, DEFAULT_DATE_FORMAT } from './constants';
17
+ import { areDatesEquals, getDateFormatter, getDateValueParser } from './helpers';
18
+ import { IDatePickerBaseProps, IRange } from './types';
19
+ import { useStyles, IDatePickerStyles } from './DatePicker.styles';
20
+
21
+ export interface IDatePickerProps extends IDatePickerBaseProps, ICommonProps<IDatePickerStyles> {
22
+ selectedDate?: Date | null;
23
+ locale: Locale;
24
+ months?: string[];
25
+ /** @default 'dd.MM.yyyy' */
26
+ dateFormat?: string;
27
+ /** @default 1 */
28
+ calendarStartDay?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
29
+ /** @default false */
30
+ isRange?: boolean;
31
+ /** @default false */
32
+ isInline?: boolean;
33
+ /** @default false */
34
+ shouldRenderPopperInBody?: boolean;
35
+ customInput?: FC<IDateInputProps>;
36
+ onChangeDate?: (date: Date | null, event?: SyntheticEvent) => void;
37
+ onChangeRange?: (date: IRange, event?: SyntheticEvent) => void;
38
+ }
39
+
40
+ export const DatePicker = forwardRef<ReactDatePicker, IDatePickerProps>(
41
+ (
42
+ {
43
+ data,
44
+ selectedDate = null,
45
+ minDate,
46
+ maxDate,
47
+ endDate = null,
48
+ startDate = null,
49
+ locale,
50
+ months,
51
+ calendarStartDay = 1,
52
+ dateFormat = DEFAULT_DATE_FORMAT,
53
+ monthsShown,
54
+ placeholder,
55
+ isRange = false,
56
+ isInline = false,
57
+ isDisabled,
58
+ isClearable,
59
+ strictParsing,
60
+ focusSelectedMonth,
61
+ disabledKeyboardNavigation,
62
+ shouldRenderPopperInBody = false,
63
+ allowSameDay = false,
64
+ shouldCloseOnSelect,
65
+ showPreviousMonths,
66
+ preventOpenOnFocus,
67
+ popperModifiers,
68
+ popperPlacement,
69
+ todayButton,
70
+ highlightDates,
71
+ calendarContainer,
72
+ dayClassName,
73
+ customInput: CustomInput = DateInput,
74
+ customInputRef,
75
+ renderCustomHeader,
76
+ filterDate,
77
+ onYearChange,
78
+ onMonthChange,
79
+ onCalendarOpen,
80
+ onCalendarClose,
81
+ onChangeDate,
82
+ onChangeRange,
83
+ onBlur,
84
+ onFocus,
85
+ onKeyDown,
86
+ tweakStyles,
87
+ ...inputProps
88
+ },
89
+ ref,
90
+ ) => {
91
+ const classes = useStyles({ theme: tweakStyles });
92
+
93
+ const tweakDateInputStyles = useTweakStyles({
94
+ tweakStyles,
95
+ className: 'tweakDateInput',
96
+ currentComponentName: 'DatePicker',
97
+ });
98
+
99
+ const { formatDate, parseDateValue } = useMemo(
100
+ () => ({
101
+ formatDate: getDateFormatter(dateFormat),
102
+ parseDateValue: getDateValueParser(dateFormat),
103
+ }),
104
+ [dateFormat],
105
+ );
106
+
107
+ const [isOpen, setIsOpen] = useState(false);
108
+
109
+ const [dateValue, setDateValue] = useState(formatDate(selectedDate));
110
+
111
+ const [start, setStart] = useState(startDate);
112
+ const [startDateValue, setStartDateValue] = useState(formatDate(startDate));
113
+ const [end, setEnd] = useState(endDate);
114
+ const [endDateValue, setEndDateValue] = useState(formatDate(endDate));
115
+
116
+ const hasDateInputValue = isRange
117
+ ? isStringNotEmpty(startDateValue) || isStringNotEmpty(endDateValue)
118
+ : isStringNotEmpty(dateValue);
119
+
120
+ const dateInputProps: IDateInputProps = {
121
+ ...inputProps,
122
+ isRange,
123
+ isDisabled,
124
+ isClearable,
125
+ isActive: isOpen,
126
+ iconType: isClearable && hasDateInputValue ? undefined : 'calendar',
127
+ tweakStyles: tweakDateInputStyles,
128
+ ...(isRange ? { startDate: startDateValue, endDate: endDateValue } : { date: dateValue }),
129
+ };
130
+
131
+ const handleChangeDate = (value: Date | null, event?: SyntheticEvent) => {
132
+ onChangeDate?.(value, event);
133
+ };
134
+
135
+ const isDateInRange = (date: Date) =>
136
+ (isEmpty(minDate) || isAfter(date, minDate)) && (isEmpty(maxDate) || isBefore(date, maxDate));
137
+
138
+ // TODO: Если пропса allowSameDay равна true и введена только начальная дата, то
139
+ // невозможно будет стереть значение в инпуте. Обойти это можно только если
140
+ // полностью выбрать период, а затем уже очищать инпут (баг в react-datepicker. В этом
141
+ // случае value равняется не [null, null], а [start, null])
142
+ const handleChangeRange = (value: IRange, event?: SyntheticEvent) => {
143
+ if (
144
+ allowSameDay ||
145
+ !areDatesEquals(value?.[0], startDate) ||
146
+ !areDatesEquals(value?.[1], endDate)
147
+ ) {
148
+ setStart(value?.[0] ?? null);
149
+ setEnd(value?.[1] ?? null);
150
+ onChangeRange?.(value, event);
151
+ }
152
+ };
153
+
154
+ const handleChangeDateRangeInput = (value: string) => {
155
+ const newStartDateValue = value.slice(0, 10);
156
+ let newStart = parseDateValue(newStartDateValue);
157
+ const newEndDateValue = value.slice(13);
158
+ let newEnd = parseDateValue(newEndDateValue);
159
+
160
+ if (
161
+ (isNotEmpty(newStart) && !isValid(newStart)) ||
162
+ (isNotEmpty(newStart) && !isDateInRange(newStart))
163
+ ) {
164
+ newStart = start;
165
+ }
166
+
167
+ if (
168
+ (isNotEmpty(newEnd) && !isValid(newEnd)) ||
169
+ (isNotEmpty(newEnd) && !isDateInRange(newEnd))
170
+ ) {
171
+ newEnd = end;
172
+ }
173
+
174
+ // Если оставить пустой начальную дату и заполненной конечную,
175
+ // то ломается react-datepicker и в календарике ничего нельзя выбирать
176
+ if (
177
+ (isEmpty(newStart) && isValid(newEnd)) ||
178
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
179
+ (isValid(newStart) && isValid(newEnd) && isAfter(newStart!, newEnd!))
180
+ ) {
181
+ newStart = newEnd;
182
+ newEnd = null;
183
+ }
184
+
185
+ setStartDateValue(newStartDateValue);
186
+ setStart(newStart);
187
+ setEndDateValue(newEndDateValue);
188
+ setEnd(newEnd);
189
+ };
190
+
191
+ const handleDateInputBlur = (event: FocusEvent<HTMLInputElement>) => {
192
+ onBlur?.(event);
193
+ setDateValue(formatDate(selectedDate));
194
+ };
195
+
196
+ const setDateRangeValues = (startValue: Date | null = null, endValue: Date | null = null) => {
197
+ let convertedStartDate = formatDate(startValue);
198
+ const convertedEndDate = formatDate(endValue);
199
+ if (convertedStartDate === '' && convertedEndDate !== '') {
200
+ // Если выставлять пустую строку, то конечная дата перепрыгивает на место начальной
201
+ convertedStartDate = EMPTY_DATE_INPUT_VALUE;
202
+ }
203
+
204
+ setStart(startValue);
205
+ setStartDateValue(convertedStartDate);
206
+ setEnd(endValue);
207
+ setEndDateValue(convertedEndDate);
208
+ };
209
+
210
+ const handleDateRangeInputBlur = (event: FocusEvent<HTMLInputElement>) => {
211
+ onBlur?.(event);
212
+ handleChangeRange([start, end], event);
213
+ setDateRangeValues(start, end);
214
+ };
215
+
216
+ const handleOpenCalendar = () => {
217
+ setIsOpen(true);
218
+ onCalendarOpen?.();
219
+ };
220
+
221
+ const handleCloseCalendar = () => {
222
+ setIsOpen(false);
223
+ if (isRange) {
224
+ handleChangeRange([start, end]);
225
+ setDateRangeValues(start, end);
226
+ } else {
227
+ setDateValue(formatDate(selectedDate));
228
+ }
229
+ onCalendarClose?.();
230
+ };
231
+
232
+ useEffect(() => {
233
+ setDateValue(formatDate(selectedDate));
234
+ setDateRangeValues(startDate, endDate);
235
+ }, [selectedDate, startDate, endDate]);
236
+
237
+ return (
238
+ <div className={classes.root} {...addDataAttributes(data)}>
239
+ <DatePickerComponent
240
+ ref={ref}
241
+ minDate={minDate}
242
+ maxDate={maxDate}
243
+ locale={locale}
244
+ dateFormat={dateFormat}
245
+ placeholderText={placeholder}
246
+ calendarStartDay={calendarStartDay}
247
+ inline={isInline}
248
+ disabled={isDisabled}
249
+ showPreviousMonths={showPreviousMonths}
250
+ focusSelectedMonth={focusSelectedMonth}
251
+ monthsShown={monthsShown}
252
+ allowSameDay={allowSameDay}
253
+ showPopperArrow={false}
254
+ popperClassName={classes.popper}
255
+ calendarClassName={classes.datepicker}
256
+ dayClassName={(v) => clsx(classes.day, dayClassName?.(v))}
257
+ disabledKeyboardNavigation={disabledKeyboardNavigation}
258
+ popperContainer={shouldRenderPopperInBody ? PopperContainer : undefined}
259
+ popperModifiers={popperModifiers}
260
+ popperPlacement={popperPlacement}
261
+ selectsRange={isRange}
262
+ strictParsing={strictParsing}
263
+ preventOpenOnFocus={preventOpenOnFocus}
264
+ shouldCloseOnSelect={shouldCloseOnSelect}
265
+ customInputRef={customInputRef}
266
+ customInput={<CustomInput {...dateInputProps} />}
267
+ renderCustomHeader={
268
+ renderCustomHeader ??
269
+ ((baseProps) => <DatePickerHeader {...baseProps} months={months} />)
270
+ }
271
+ todayButton={todayButton}
272
+ highlightDates={highlightDates}
273
+ calendarContainer={calendarContainer}
274
+ filterDate={filterDate}
275
+ onYearChange={onYearChange}
276
+ onMonthChange={onMonthChange}
277
+ onFocus={onFocus}
278
+ onKeyDown={onKeyDown}
279
+ onCalendarOpen={handleOpenCalendar}
280
+ onCalendarClose={handleCloseCalendar}
281
+ onChangeRaw={(_, value?: string) => {
282
+ // Если передали value, значит этот обработчик вызвался после изменения значения в инпуте
283
+ // (react-datepicker вызывает эту функцию также при клике на дату в календаре)
284
+ if (value === undefined) {
285
+ return;
286
+ }
287
+ if (isRange) {
288
+ handleChangeDateRangeInput(value);
289
+ } else {
290
+ setDateValue(value);
291
+ }
292
+ }}
293
+ {...(isRange
294
+ ? {
295
+ startDate: start,
296
+ endDate: end,
297
+ selected: start,
298
+ onBlur: handleDateRangeInputBlur,
299
+ onChange: handleChangeRange,
300
+ }
301
+ : {
302
+ selected: selectedDate,
303
+ onBlur: handleDateInputBlur,
304
+ onChange: handleChangeDate,
305
+ })}
306
+ />
307
+ </div>
308
+ );
309
+ },
310
+ );
@@ -29,6 +29,7 @@ export type IDatePickerBaseProps = Pick<
29
29
  | 'customInputRef'
30
30
  | 'preventOpenOnFocus'
31
31
  | 'strictParsing'
32
+ | 'highlightDates'
32
33
  > &
33
34
  Omit<
34
35
  IDateInputProps,