kamotive_ui 1.2.22 → 1.2.23

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.
@@ -7,17 +7,20 @@ import { IconCalendar } from '../../Icons/IconCalendar/IconCalendar';
7
7
  import 'react-datepicker/dist/react-datepicker.css';
8
8
  import { registerLocale } from 'react-datepicker';
9
9
  import { ru } from 'date-fns/locale/ru';
10
+ import { enUS } from 'date-fns/locale/en-US';
10
11
  import { ChevronRight } from '../../Icons/ChevronRight/ChevronRight';
11
12
  import { ChevronLeft } from '../../Icons/ChevronLeft/ChevronLeft';
12
13
  import { Button } from '../Button/Button';
13
14
  registerLocale('ru', ru);
14
- const CustomInput = forwardRef(({ value = '', onClick, onDateChange, onClose, className, disabled = false, readOnly = false }, ref) => {
15
+ registerLocale('en', enUS);
16
+ const CustomInput = forwardRef(({ value = '', onClick, onDateChange, onClose, className, disabled = false, readOnly = false, dateFormat = 'dd.MM.yyyy' }, ref) => {
15
17
  const inputRef = useRef(null);
16
18
  const [selectedPart, setSelectedPart] = useState(null);
17
19
  const [tempInput, setTempInput] = useState('');
18
20
  const [hasFocus, setHasFocus] = useState(false);
19
21
  const [shouldReselect, setShouldReselect] = useState(false);
20
22
  const [input, setInput] = useState(value);
23
+ const separator = dateFormat.includes('.') ? '.' : dateFormat.includes('-') ? '-' : '/';
21
24
  const positions = {
22
25
  day: { start: 0, end: 2 },
23
26
  month: { start: 3, end: 5 },
@@ -74,7 +77,7 @@ const CustomInput = forwardRef(({ value = '', onClick, onDateChange, onClose, cl
74
77
  selectDatePart('month');
75
78
  }
76
79
  }
77
- else if (e.key === 'ArrowRight' || e.key === '.') {
80
+ else if (e.key === 'ArrowRight' || e.key === separator) {
78
81
  e.preventDefault();
79
82
  if (selectedPart === 'day') {
80
83
  selectDatePart('month');
@@ -85,12 +88,13 @@ const CustomInput = forwardRef(({ value = '', onClick, onDateChange, onClose, cl
85
88
  }
86
89
  else if (/^\d$/.test(e.key)) {
87
90
  e.preventDefault();
88
- if (!/^\d{2}\.\d{2}\.\d{4}$/.test(input)) {
91
+ const dateRegex = new RegExp(`^\\d{2}\\${separator}\\d{2}\\${separator}\\d{4}$`);
92
+ if (!dateRegex.test(input)) {
89
93
  const today = new Date();
90
94
  handleDateUpdate(today, e.key);
91
95
  return;
92
96
  }
93
- const [day, month, year] = input.split('.').map((part) => parseInt(part, 10));
97
+ const [day, month, year] = input.split(separator).map((part) => parseInt(part, 10));
94
98
  const currentDate = new Date(year, month - 1, day);
95
99
  handleDateUpdate(currentDate, e.key);
96
100
  }
@@ -141,7 +145,7 @@ const CustomInput = forwardRef(({ value = '', onClick, onDateChange, onClose, cl
141
145
  updateInputValue(key, positions.month.start);
142
146
  return;
143
147
  }
144
- updateInputValue(key, positions.day.start + 1);
148
+ updateInputValue(key, positions.month.start + 1);
145
149
  let newMonth = parseInt(newTempInput, 10);
146
150
  newDate.setMonth(newMonth - 1);
147
151
  onDateChange(newDate);
@@ -189,9 +193,9 @@ const CustomInput = forwardRef(({ value = '', onClick, onDateChange, onClose, cl
189
193
  useImperativeHandle(ref, () => ({
190
194
  removeSelection,
191
195
  }), [removeSelection]);
192
- return (React.createElement("input", { ref: inputRef, value: input, onClick: handleClick, onKeyDown: handleKeyDown, onFocus: handleFocus, onBlur: handleBlur, readOnly: readOnly, disabled: disabled, className: className }));
196
+ return (React.createElement("input", { ref: inputRef, value: input, onClick: handleClick, onKeyDown: handleKeyDown, onFocus: handleFocus, onBlur: handleBlur, onChange: () => { }, readOnly: readOnly, disabled: disabled, className: className }));
193
197
  });
194
- export const DateInput = ({ id, label = 'Выберите дату', size = 'lg', value, style, className, disabled = false, readOnly = false, isLeftLabel = false, icon, error = false, helperText, onChange, onBlur, required = false, minDate = new Date('1975-12-31'), maxDate = new Date('2074-12-31'), inputClassName, calendarClassName, dateFormat = 'dd.MM.yyyy', }) => {
198
+ export const DateInput = ({ id, label = 'Выберите дату', size = 'lg', value, style, className, disabled = false, readOnly = false, isLeftLabel = false, icon, error = false, helperText, onChange, onBlur, required = false, lng = 'ru', minDate = new Date('1975-12-31'), maxDate = new Date('2074-12-31'), inputClassName, calendarClassName, dateFormat = 'dd.MM.yyyy', }) => {
195
199
  const wrapperClassess = classNames(styles['wrapper--input'], className, {
196
200
  [styles['wrapper--left']]: isLeftLabel,
197
201
  [styles['wrapper--input-label']]: label && !isLeftLabel && !required,
@@ -212,20 +216,36 @@ export const DateInput = ({ id, label = 'Выберите дату', size = 'lg'
212
216
  const [isMonthPickerOpen, setIsMonthPickerOpen] = useState(false);
213
217
  const datePickerRef = useRef(null);
214
218
  const inputRef = useRef(null);
215
- const months = [
216
- 'Январь',
217
- 'Февраль',
218
- 'Март',
219
- 'Апрель',
220
- 'Май',
221
- 'Июнь',
222
- 'Июль',
223
- 'Август',
224
- 'Сентябрь',
225
- 'Октябрь',
226
- 'Ноябрь',
227
- 'Декабрь',
228
- ];
219
+ const weekDays = lng === 'ru' ? ['Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс'] : ['Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su'];
220
+ const months = lng === 'ru'
221
+ ? [
222
+ 'Январь',
223
+ 'Февраль',
224
+ 'Март',
225
+ 'Апрель',
226
+ 'Май',
227
+ 'Июнь',
228
+ 'Июль',
229
+ 'Август',
230
+ 'Сентябрь',
231
+ 'Октябрь',
232
+ 'Ноябрь',
233
+ 'Декабрь',
234
+ ]
235
+ : [
236
+ 'January',
237
+ 'February',
238
+ 'March',
239
+ 'April',
240
+ 'May',
241
+ 'June',
242
+ 'July',
243
+ 'August',
244
+ 'September',
245
+ 'October',
246
+ 'November',
247
+ 'December',
248
+ ];
229
249
  const years = Array.from({ length: maxDate.getFullYear() - minDate.getFullYear() }, (_, i) => minDate.getFullYear() + i);
230
250
  const handleDateChange = (date) => {
231
251
  if (date) {
@@ -297,12 +317,12 @@ export const DateInput = ({ id, label = 'Выберите дату', size = 'lg'
297
317
  React.createElement("div", { className: styles.buttonContainer },
298
318
  React.createElement(Button, { condition: "info", onClick: () => {
299
319
  setIsMonthPickerOpen(false);
300
- } }, "\u041E\u0442\u043C\u0435\u043D\u0430"),
320
+ } }, lng === 'ru' ? "Отмена" : "Cancel"),
301
321
  React.createElement(Button, { onClick: () => {
302
322
  date.setMonth(currentMonth);
303
323
  date.setFullYear(currentYear);
304
324
  setIsMonthPickerOpen(false);
305
- } }, "\u041F\u0440\u0438\u043C\u0435\u043D\u0438\u0442\u044C"))));
325
+ } }, lng === 'ru' ? "Применить" : "Apply"))));
306
326
  };
307
327
  const getMonthPickerWithDate = (date) => {
308
328
  return () => React.createElement(MonthPicker, { date: date });
@@ -326,7 +346,11 @@ export const DateInput = ({ id, label = 'Выберите дату', size = 'lg'
326
346
  return (React.createElement("div", { className: wrapperClassess, style: style },
327
347
  label && (React.createElement(Typography, { variant: "Caption", className: labelClasses }, label)),
328
348
  React.createElement("div", { className: styles.icon, onClick: () => { var _a; return (_a = datePickerRef.current) === null || _a === void 0 ? void 0 : _a.setOpen(true); } }, icon || React.createElement(IconCalendar, null)),
329
- React.createElement(DatePicker, Object.assign({ id: id, ref: datePickerRef, selected: selectedDate, onChange: handleDateChange, onBlur: onBlur, dateFormat: dateFormat, locale: "ru", readOnly: readOnly, disabled: disabled, showPopperArrow: false, calendarClassName: classNames(styles.calendar, calendarClassName), popperClassName: styles.calendarPopper, onCalendarClose: () => setIsMonthPickerOpen(false), minDate: minDate, maxDate: maxDate, inline: false, calendarStartDay: 1, dayClassName: (date) => {
349
+ React.createElement(DatePicker, Object.assign({ id: id, ref: datePickerRef, selected: selectedDate, onChange: handleDateChange, onBlur: onBlur, dateFormat: dateFormat, locale: lng === 'ru' ? 'ru' : 'en', readOnly: readOnly, disabled: disabled, showPopperArrow: false, calendarClassName: classNames(styles.calendar, calendarClassName), popperClassName: styles.calendarPopper, onCalendarClose: () => setIsMonthPickerOpen(false), minDate: minDate, maxDate: maxDate, inline: false, calendarStartDay: 1, formatWeekDay: (dayName) => {
350
+ const dayIndex = ['понедельник', 'вторник', 'среда', 'четверг', 'пятница', 'суббота', 'воскресенье']
351
+ .findIndex(day => day === dayName);
352
+ return weekDays[dayIndex];
353
+ }, dayClassName: (date) => {
330
354
  return date.getMonth() === (selectedDate === null || selectedDate === void 0 ? void 0 : selectedDate.getMonth()) && date.getFullYear() === (selectedDate === null || selectedDate === void 0 ? void 0 : selectedDate.getFullYear())
331
355
  ? 'current-month-day'
332
356
  : '';
@@ -335,6 +359,6 @@ export const DateInput = ({ id, label = 'Выберите дату', size = 'lg'
335
359
  : {
336
360
  renderCustomHeader: renderCustomHeader,
337
361
  renderDayContents: renderDayContents,
338
- }), { customInput: React.createElement(CustomInput, { ref: inputRef, className: classNames(inputClassess, inputClassName), onDateChange: handleCustomInputChange, onClose: handleCloseDatePicker, disabled: disabled, readOnly: readOnly }) })),
362
+ }), { customInput: React.createElement(CustomInput, { ref: inputRef, className: classNames(inputClassess, inputClassName), onDateChange: handleCustomInputChange, onClose: handleCloseDatePicker, disabled: disabled, readOnly: readOnly, dateFormat: dateFormat }) })),
339
363
  error && helperText && (React.createElement(Typography, { variant: "Caption", className: classNames(styles.helperText, styles[size]) }, helperText))));
340
364
  };
@@ -5,8 +5,13 @@ import { ChevronDown } from '../../Icons/ChevronDown/ChevronDown';
5
5
  import { ChevronUp } from '../../Icons/ChevronUp/ChevronUp';
6
6
  import { IconClose } from '../../Icons/IconClose/IconClose';
7
7
  import { IconCheck } from '../../Icons/IconCheck/IconCheck';
8
- ;
9
8
  import { Typography } from '../Typography/Typography';
9
+ import { Tooltip } from '../Tooltip/Tooltip';
10
+ const isTextOverflowing = (element) => {
11
+ if (!element)
12
+ return false;
13
+ return element.scrollWidth > element.clientWidth;
14
+ };
10
15
  function checkItem(item, getOptionLabel, disabled, isDivider) {
11
16
  if (typeof item === 'object' && item !== null) {
12
17
  const itemCopy = Object.assign({}, item);
@@ -53,7 +58,19 @@ function checkItem(item, getOptionLabel, disabled, isDivider) {
53
58
  }
54
59
  }
55
60
  export const DropdownListItem = ({ item, getOptionLabel, size = 'md', selectedItem, variant, onChange, isActive, activeIndex, index, }) => {
56
- var _a;
61
+ var _a, _b;
62
+ const itemRef = useRef(null);
63
+ const [showTooltip, setShowTooltip] = useState(false);
64
+ useEffect(() => {
65
+ const checkOverflow = () => {
66
+ setShowTooltip(isTextOverflowing(itemRef.current));
67
+ };
68
+ checkOverflow();
69
+ window.addEventListener('resize', checkOverflow);
70
+ return () => {
71
+ window.removeEventListener('resize', checkOverflow);
72
+ };
73
+ }, [item === null || item === void 0 ? void 0 : item.value]);
57
74
  const handleItemClick = useCallback((event) => {
58
75
  event.preventDefault();
59
76
  event.stopPropagation();
@@ -67,7 +84,7 @@ export const DropdownListItem = ({ item, getOptionLabel, size = 'md', selectedIt
67
84
  [styles['item-block--active']]: isActive,
68
85
  });
69
86
  const itemBlock = classNames(styles[`item-block`], styles[`item-block-${variant}`], { [styles[`item-block-${variant}--selected`]]: (selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.value) === (item === null || item === void 0 ? void 0 : item.value) }, { [styles['item-block--disabled']]: item === null || item === void 0 ? void 0 : item.disabled });
70
- return (React.createElement("div", { className: itemContainerClasses, onClick: handleItemClick },
87
+ const itemContent = (React.createElement("div", { className: itemContainerClasses, onClick: handleItemClick },
71
88
  React.createElement("div", { className: itemClassess },
72
89
  React.createElement("div", { className: itemBlock },
73
90
  variant === 'icons' &&
@@ -75,7 +92,7 @@ export const DropdownListItem = ({ item, getOptionLabel, size = 'md', selectedIt
75
92
  React.cloneElement(item.icon, {
76
93
  strokeWidth: size === 'lg' ? '0.5' : size === 'md' ? '0.3' : '0.0',
77
94
  }),
78
- React.createElement("div", { className: styles.item },
95
+ React.createElement("div", { className: styles.item, ref: itemRef },
79
96
  React.createElement("span", null, item === null || item === void 0 ? void 0 : item.value)),
80
97
  (selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.value) === (item === null || item === void 0 ? void 0 : item.value) && (React.createElement(IconCheck, { strokeWidth: size === 'lg' ? '0.5' : size === 'md' ? '0.3' : '0.0', htmlColor: "#0D99FF" }))),
81
98
  (item === null || item === void 0 ? void 0 : item.isDivider) && React.createElement("div", { className: styles.divider })),
@@ -83,6 +100,7 @@ export const DropdownListItem = ({ item, getOptionLabel, size = 'md', selectedIt
83
100
  var _a;
84
101
  return (React.createElement(DropdownListItem, { key: (_a = child === null || child === void 0 ? void 0 : child.key) !== null && _a !== void 0 ? _a : childIndex, item: child, getOptionLabel: getOptionLabel, size: size, selectedItem: selectedItem, onChange: onChange, isActive: activeIndex === index, activeIndex: activeIndex, index: childIndex }));
85
102
  })))));
103
+ return showTooltip ? (React.createElement(Tooltip, { label: ((_b = item === null || item === void 0 ? void 0 : item.value) === null || _b === void 0 ? void 0 : _b.toString()) || '', position: "bottom-left" }, itemContent)) : (itemContent);
86
104
  };
87
105
  export const Dropdown = ({ options, id, label, placeholder, required = false, value, defaultValue, onChange, getOptionLabel, variant = 'text', size = 'lg', style, className, isLeftLabel = false, isDivider = false, disabled = false, readOnly = false, isOpened = false, error = false, helperText, onClick, onBlur, onFocus, onClose, clearable = true, enableAutocomplete = false, noOptionsText = 'Нет вариантов для выбора', }) => {
88
106
  const [isOpen, setIsOpen] = useState(isOpened);
@@ -244,9 +262,21 @@ export const Dropdown = ({ options, id, label, placeholder, required = false, va
244
262
  setErrorInputHelperText(helperText !== null && helperText !== void 0 ? helperText : 'Поле обязательно для заполнения');
245
263
  }
246
264
  };
265
+ const [showSelectedTooltip, setShowSelectedTooltip] = useState(false);
266
+ const selectedItemRef = useRef(null);
267
+ useEffect(() => {
268
+ const checkOverflow = () => {
269
+ setShowSelectedTooltip(isTextOverflowing(selectedItemRef.current));
270
+ };
271
+ checkOverflow();
272
+ window.addEventListener('resize', checkOverflow);
273
+ return () => {
274
+ window.removeEventListener('resize', checkOverflow);
275
+ };
276
+ }, [selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.value]);
247
277
  const getTextField = () => {
248
- var _a;
249
- return (React.createElement("div", { className: selectedItemClassess },
278
+ var _a, _b;
279
+ const textFieldContent = (React.createElement("div", { className: selectedItemClassess, ref: selectedItemRef },
250
280
  variant === 'icons' &&
251
281
  (selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.icon) &&
252
282
  React.cloneElement(selectedItem.icon, {
@@ -266,6 +296,8 @@ export const Dropdown = ({ options, id, label, placeholder, required = false, va
266
296
  e.stopPropagation();
267
297
  onBlur === null || onBlur === void 0 ? void 0 : onBlur(e);
268
298
  }, onKeyDown: handleKeyDown, autoFocus: true })) : selectedItem ? (selectedItem.value) : (searchValue || ((_a = placeholder !== null && placeholder !== void 0 ? placeholder : label) !== null && _a !== void 0 ? _a : 'Выберите значение'))));
299
+ return showSelectedTooltip ? (React.createElement("div", { className: styles.textField },
300
+ React.createElement(Tooltip, { label: ((_b = selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.value) === null || _b === void 0 ? void 0 : _b.toString()) || '', position: "bottom-left", style: { width: '100% !important' } }, textFieldContent))) : (textFieldContent);
269
301
  };
270
302
  const getDropdownMenu = () => {
271
303
  const optionsToRender = enableAutocomplete && searchValue
@@ -340,9 +372,10 @@ export const Dropdown = ({ options, id, label, placeholder, required = false, va
340
372
  label && (React.createElement(Typography, { variant: "Caption", className: labelClasses }, label)),
341
373
  React.createElement("button", { className: buttonClassess, onClick: readOnly ? undefined : handleToggle, disabled: disabled, tabIndex: 0, onKeyDown: handleKeyDown },
342
374
  getTextField(),
343
- clearable && !readOnly && !disabled && (selectedItem || enableAutocomplete && searchValue) && (React.createElement("div", { className: styles.resetButton },
344
- React.createElement(IconClose, { strokeWidth: "0.2", htmlColor: "var(--text-light)", onClick: handleReset }))),
345
- React.createElement("div", { className: styles.dropdownIcon }, !isOpen ? (React.createElement(ChevronDown, { strokeWidth: size === 'lg' ? '0.5' : '0.3' })) : (React.createElement(ChevronUp, { strokeWidth: size === 'lg' ? '0.5' : '0.3' }))),
375
+ React.createElement("div", { className: styles.actionButtons },
376
+ clearable && !readOnly && !disabled && (selectedItem || enableAutocomplete && searchValue) && (React.createElement("div", { className: styles.resetButton },
377
+ React.createElement(IconClose, { strokeWidth: "0.2", htmlColor: "var(--text-light)", onClick: handleReset }))),
378
+ React.createElement("div", { className: styles.dropdownIcon }, !isOpen ? (React.createElement(ChevronDown, { strokeWidth: size === 'lg' ? '0.5' : '0.3' })) : (React.createElement(ChevronUp, { strokeWidth: size === 'lg' ? '0.5' : '0.3' })))),
346
379
  getDropdownMenu()),
347
380
  errorInput && errorInputHelperText && (React.createElement(Typography, { variant: "Caption", className: classNames(styles.helperText, styles[size]) }, helperText !== null && helperText !== void 0 ? helperText : errorInputHelperText))));
348
381
  };
@@ -1,7 +1,6 @@
1
1
  .dropdown--container {
2
2
  position: relative;
3
3
  width: 100%;
4
- max-width: 260px;
5
4
  }
6
5
  .dropdown--container-left {
7
6
  display: flex;
@@ -35,17 +34,15 @@
35
34
  line-height: 16.5px;
36
35
  border-radius: 10px;
37
36
  cursor: pointer;
38
- padding: 10px 15px;
37
+ padding: 6px 12px;
39
38
  transition: all 0.3s ease;
40
39
  background-color: transparent;
41
40
  color: var(--text-dark);
42
41
  border: 1px solid var(--grey-mediumLight);
43
- /* mix-blend-mode: multiply; */
44
42
  display: flex;
45
43
  align-items: center;
46
44
  gap: 20px;
47
45
  justify-content: space-between;
48
- /* min-width: fit-content; */
49
46
  position: relative;
50
47
  width: 100%;
51
48
  }
@@ -100,10 +97,15 @@
100
97
  .button:focus-visible {
101
98
  outline: none;
102
99
  }
103
-
100
+ .actionButtons {
101
+ display: flex;
102
+ gap: 0px;
103
+ align-items: center;
104
+ margin-right: -6px;
105
+ }
104
106
  .resetButton,
105
107
  .dropdownIcon {
106
- position: absolute;
108
+ /* position: absolute; */
107
109
  background: none;
108
110
  border: none;
109
111
  cursor: pointer;
@@ -143,6 +145,20 @@
143
145
  overflow-x: hidden;
144
146
  }
145
147
 
148
+ .textField{
149
+ width: 100%;
150
+ overflow: hidden;
151
+ }
152
+
153
+ .textField > :first-child {
154
+ width: 100%;
155
+ overflow: hidden;
156
+ text-overflow: ellipsis;
157
+ white-space: nowrap;
158
+ min-width: 0;
159
+ display: block;
160
+ }
161
+
146
162
  .inlineSearchInput {
147
163
  border: none;
148
164
  outline: none;
@@ -255,13 +271,13 @@
255
271
 
256
272
  .item-selected {
257
273
  color: var(--text-dark);
258
- width: 80%;
259
274
  overflow: hidden;
260
275
  text-overflow: ellipsis;
261
276
  white-space: nowrap;
262
277
  min-width: 0;
263
278
  text-align: left;
264
279
  position: relative;
280
+ flex: 1;
265
281
  }
266
282
 
267
283
  .item-selected .inlineSearchInput {
@@ -1,6 +1,5 @@
1
1
  .wrapper--input {
2
2
  position: relative;
3
- max-width: 260px;
4
3
  width: 100%;
5
4
  }
6
5
  .wrapper--input-label {
@@ -18,5 +18,5 @@
18
18
  }
19
19
 
20
20
  .wrapper {
21
- width: fit-content;
21
+ width: 100%;
22
22
  }
@@ -124,6 +124,8 @@ export interface DateInputProps {
124
124
  onBlur?: React.FocusEventHandler<HTMLElement>;
125
125
  /** Обязательное поле */
126
126
  required?: boolean;
127
+ /** Язык */
128
+ lng?: string;
127
129
  }
128
130
  /** @internal */
129
131
  export interface TagProps {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kamotive_ui",
3
- "version": "1.2.22",
3
+ "version": "1.2.23",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "files": [