kamotive_ui 2.10.5 → 8.12.25
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.
- package/dist/components/AttachedFilesPreview/AttachedFilesPreview.d.ts +3 -1
- package/dist/components/AttachedFilesPreview/AttachedFilesPreview.js +9 -6
- package/dist/components/Comment/Comment.js +5 -5
- package/dist/components/Comment/Comment.module.css +1 -1
- package/dist/components/Dropdown/Dropdown.js +14 -8
- package/dist/components/Dropdown/Dropdown.module.css +13 -0
- package/dist/components/FileAttach/FileAttach.js +5 -2
- package/dist/components/FileItem/FileItem.js +2 -2
- package/dist/components/FileListAttached/FileListAtta/321/201hed.js +1 -1
- package/dist/components/FileLoader/FileLoader.d.ts +3 -3
- package/dist/components/FileLoader/FileLoader.js +49 -14
- package/dist/components/IconButton/IconButton.module.css +1 -0
- package/dist/components/TextEditor/TextEditor.js +3 -2
- package/dist/types/index.d.ts +20 -0
- package/package.json +2 -2
|
@@ -3,9 +3,10 @@ export interface FilePreview {
|
|
|
3
3
|
file: File;
|
|
4
4
|
id: string;
|
|
5
5
|
preview?: string;
|
|
6
|
+
lng: string;
|
|
6
7
|
}
|
|
7
8
|
export declare const getFileIcon: (file: File) => React.JSX.Element;
|
|
8
|
-
export declare const formatFileSize: (bytes?: number) => string;
|
|
9
|
+
export declare const formatFileSize: (bytes?: number, lng?: string) => string;
|
|
9
10
|
interface AttachedFilesProps {
|
|
10
11
|
files: FilePreview[];
|
|
11
12
|
onDelete?: (id: string) => void;
|
|
@@ -14,6 +15,7 @@ interface AttachedFilesProps {
|
|
|
14
15
|
className?: string;
|
|
15
16
|
isEdit?: boolean;
|
|
16
17
|
allowDownload?: boolean;
|
|
18
|
+
lng: string;
|
|
17
19
|
}
|
|
18
20
|
export declare const AttachedFilesPreview: React.FC<AttachedFilesProps>;
|
|
19
21
|
export {};
|
|
@@ -31,15 +31,18 @@ export const getFileIcon = (file) => {
|
|
|
31
31
|
return React.createElement(IconFileDefault, null);
|
|
32
32
|
};
|
|
33
33
|
// Функция для форматирования размера файла
|
|
34
|
-
export const formatFileSize = (bytes) => {
|
|
35
|
-
if (!bytes || bytes === 0)
|
|
36
|
-
return '0 Bytes';
|
|
34
|
+
export const formatFileSize = (bytes, lng) => {
|
|
35
|
+
if (!bytes || bytes === 0) {
|
|
36
|
+
return lng === 'ru' || (lng === null || lng === void 0 ? void 0 : lng.includes('ru')) ? '0 Байт' : '0 Bytes';
|
|
37
|
+
}
|
|
37
38
|
const k = 1024;
|
|
38
|
-
const
|
|
39
|
+
const sizesEn = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
|
|
40
|
+
const sizesRu = ['Байт', 'КБ', 'МБ', 'ГБ', 'ТБ'];
|
|
39
41
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
42
|
+
const sizes = lng === 'ru' || (lng === null || lng === void 0 ? void 0 : lng.includes('ru')) ? sizesRu : sizesEn;
|
|
40
43
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
|
41
44
|
};
|
|
42
|
-
export const AttachedFilesPreview = ({ files, onDelete, onDownload, style, className, isEdit, allowDownload = true, }) => {
|
|
45
|
+
export const AttachedFilesPreview = ({ files, onDelete, onDownload, style, className, isEdit, allowDownload = true, lng, }) => {
|
|
43
46
|
const handleDelete = (event, id) => {
|
|
44
47
|
event.stopPropagation();
|
|
45
48
|
if (onDelete) {
|
|
@@ -65,5 +68,5 @@ export const AttachedFilesPreview = ({ files, onDelete, onDownload, style, class
|
|
|
65
68
|
React.createElement("div", { onClick: allowDownload ? () => handleDownload(file.file) : undefined, className: styles.filePreview },
|
|
66
69
|
file.preview ? (React.createElement("img", { src: file.preview, alt: file.file.name, className: styles.previewImage })) : (React.createElement("div", { className: styles.previewImage }, getFileIcon(file.file))),
|
|
67
70
|
isEdit && (React.createElement("button", { className: styles.removeFileButton, onClick: (event) => handleDelete(event, file.id) }, "\u2715")),
|
|
68
|
-
React.createElement("div", { className: styles.fileSize }, formatFileSize(file.file.size))))))));
|
|
71
|
+
React.createElement("div", { className: styles.fileSize }, formatFileSize(file.file.size, lng))))))));
|
|
69
72
|
};
|
|
@@ -6,7 +6,7 @@ import { TextEditor } from '../TextEditor/TextEditor';
|
|
|
6
6
|
import { AttachedFilesPreview } from '../AttachedFilesPreview/AttachedFilesPreview';
|
|
7
7
|
import { IconAccount, IconDeleteFilled, IconPencilFilled } from '../../Icons';
|
|
8
8
|
import { IconButton } from '../IconButton/IconButton';
|
|
9
|
-
export const Comment = ({ id, value, style, className, username, avatar, creationDate, canAttachFiles = false, files = [], canEdit = false, isEdit = false, label, error = false, helperText, onChange, onSubmit, onDelete, }) => {
|
|
9
|
+
export const Comment = ({ id, value, style, className, username, avatar, creationDate, canAttachFiles = false, files = [], canEdit = false, isEdit = false, label, error = false, helperText, onChange, onSubmit, onDelete, lng = 'ru', }) => {
|
|
10
10
|
const [commentText, setCommentText] = useState(value || '');
|
|
11
11
|
const [isEditMode, setIsEditMode] = useState(isEdit);
|
|
12
12
|
const [attachedFiles, setAttachedFiles] = useState(files);
|
|
@@ -45,10 +45,10 @@ export const Comment = ({ id, value, style, className, username, avatar, creatio
|
|
|
45
45
|
React.createElement(Typography, { variant: "Body2-Medium", className: labelClasses }, username),
|
|
46
46
|
React.createElement(Typography, { variant: "Caption", className: styles.label, style: { color: '#8E8E93' } }, creationDate))),
|
|
47
47
|
canEdit && (React.createElement("div", { className: styles.iconsWrapper },
|
|
48
|
-
React.createElement(IconButton, { icon: React.createElement(IconPencilFilled, null), onClick: handleEditClick, size: "sm", style: { aspectRatio: 0 } }),
|
|
49
|
-
React.createElement(IconButton, { icon: React.createElement(IconDeleteFilled, null), onClick: handleDeleteClick, size: "sm", style: { aspectRatio: 0 } })))),
|
|
50
|
-
isEditMode ? (React.createElement(TextEditor, { defaultValue: commentText, onSubmit: handleSubmit, onChange: handleChange, error: error, helperText: helperText, files: attachedFiles, canAttachFiles: canAttachFiles })) : (React.createElement("div", { className: styles.commentWrapper },
|
|
51
|
-
attachedFiles.length > 0 && (React.createElement(AttachedFilesPreview, { files: attachedFiles, className: styles.attachedFilesContainer })),
|
|
48
|
+
React.createElement(IconButton, { icon: React.createElement(IconPencilFilled, null), onClick: handleEditClick, size: "sm", style: { aspectRatio: 0, width: '30px', height: '30px' } }),
|
|
49
|
+
React.createElement(IconButton, { icon: React.createElement(IconDeleteFilled, null), onClick: handleDeleteClick, size: "sm", style: { aspectRatio: 0, width: '30px', height: '30px' } })))),
|
|
50
|
+
isEditMode ? (React.createElement(TextEditor, { defaultValue: commentText, onSubmit: handleSubmit, onChange: handleChange, error: error, helperText: helperText, files: attachedFiles, canAttachFiles: canAttachFiles, lng: lng })) : (React.createElement("div", { className: styles.commentWrapper },
|
|
51
|
+
attachedFiles.length > 0 && (React.createElement(AttachedFilesPreview, { files: attachedFiles, className: styles.attachedFilesContainer, lng: lng })),
|
|
52
52
|
React.createElement("div", { id: id, className: inputClassess, dangerouslySetInnerHTML: { __html: commentText || '' } }))),
|
|
53
53
|
error && helperText && (React.createElement(Typography, { variant: "Caption", className: classNames(styles.helperText) }, helperText))));
|
|
54
54
|
};
|
|
@@ -168,11 +168,11 @@ export const DropdownListItem = ({ item, getOptionLabel, size = 'md', selectedIt
|
|
|
168
168
|
(item === null || item === void 0 ? void 0 : item.isDivider) && React.createElement("div", { className: styles.divider })),
|
|
169
169
|
hasChildren && (React.createElement("div", { className: styles.nestedMenu }, (_a = item.children) === null || _a === void 0 ? void 0 : _a.map((child, childIndex) => {
|
|
170
170
|
var _a;
|
|
171
|
-
return (React.createElement(DropdownListItem, { key: (_a = child === null || child === void 0 ? void 0 : child.
|
|
171
|
+
return (React.createElement(DropdownListItem, { key: (_a = child === null || child === void 0 ? void 0 : child.id) !== null && _a !== void 0 ? _a : `${index}-${childIndex}`, item: child, getOptionLabel: getOptionLabel, size: size, selectedItem: selectedItem, onChange: onChange, isActive: false, activeIndex: activeIndex, index: childIndex, isChild: true }));
|
|
172
172
|
})))));
|
|
173
173
|
return showTooltip ? (React.createElement(Tooltip, { label: ((_b = getComparisonValue(item, getOptionLabel)) === null || _b === void 0 ? void 0 : _b.toString()) || '', position: "bottom-left" }, itemContent)) : (itemContent);
|
|
174
174
|
};
|
|
175
|
-
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 = 'Нет вариантов для выбора', lng = 'ru', }) => {
|
|
175
|
+
export const Dropdown = ({ options, id, label, placeholder, required = false, value, defaultValue, onChange, showLoadMore = false, loadMore, 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 = 'Нет вариантов для выбора', lng = 'ru', }) => {
|
|
176
176
|
const [isOpen, setIsOpen] = useState(isOpened);
|
|
177
177
|
const [modifiedOptions, setModifiedOptions] = useState([]);
|
|
178
178
|
const [selectedItem, setSelectedItem] = useState(null);
|
|
@@ -373,12 +373,18 @@ export const Dropdown = ({ options, id, label, placeholder, required = false, va
|
|
|
373
373
|
};
|
|
374
374
|
const getDropdownMenu = () => {
|
|
375
375
|
const optionsToRender = enableAutocomplete && searchValue ? filteredOptions : modifiedOptions;
|
|
376
|
-
const menu = isOpen && (React.createElement("div", { className: dropdownClassess },
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
376
|
+
const menu = isOpen && (React.createElement("div", { className: dropdownClassess },
|
|
377
|
+
optionsToRender && optionsToRender.length > 0 ? (optionsToRender.map((optionsToRender, index) => {
|
|
378
|
+
var _a;
|
|
379
|
+
return (React.createElement(DropdownListItem, { key: (_a = optionsToRender === null || optionsToRender === void 0 ? void 0 : optionsToRender.id) !== null && _a !== void 0 ? _a : index, item: optionsToRender, getOptionLabel: getOptionLabel, size: size, selectedItem: selectedItem, variant: variant, onChange: onChangeHandler, isActive: activeIndex === index, activeIndex: activeIndex, index: index }));
|
|
380
|
+
})) : (React.createElement("div", { className: `${styles['item-container']} ${styles['item-block']}`, style: { paddingLeft: '15px' } }, lng === 'ru' || lng.includes('ru')
|
|
381
|
+
? noOptionsText || 'Нет вариантов для выбора'
|
|
382
|
+
: noOptionsText || 'No options to select')),
|
|
383
|
+
showLoadMore && loadMore && React.createElement("div", { className: styles[`loadMore`], onClick: (e) => {
|
|
384
|
+
e.stopPropagation();
|
|
385
|
+
e.preventDefault();
|
|
386
|
+
loadMore();
|
|
387
|
+
} }, 'Загрузить еще')));
|
|
382
388
|
return isOpen ? menu : null;
|
|
383
389
|
};
|
|
384
390
|
useEffect(() => {
|
|
@@ -337,3 +337,16 @@
|
|
|
337
337
|
grid-template-columns: 1fr 20px;
|
|
338
338
|
justify-content: space-between;
|
|
339
339
|
}
|
|
340
|
+
/* Кнопка Загрузить еще */
|
|
341
|
+
.loadMore {
|
|
342
|
+
/* align-self: flex-end; */
|
|
343
|
+
padding: 6px;
|
|
344
|
+
margin-left: 10px;
|
|
345
|
+
font-size: 12px;
|
|
346
|
+
color: var(--blue-secondary);
|
|
347
|
+
cursor: pointer;
|
|
348
|
+
|
|
349
|
+
}
|
|
350
|
+
.loadMore:hover {
|
|
351
|
+
color: var(--blue-dark);
|
|
352
|
+
}
|
|
@@ -3,15 +3,18 @@ import styles from './FileAttach.module.css';
|
|
|
3
3
|
import classNames from 'classnames';
|
|
4
4
|
import { FileLoader } from '../FileLoader/FileLoader';
|
|
5
5
|
import { FileListAttaсhed } from '../FileListAttached/FileListAttaсhed';
|
|
6
|
-
export const FileAttach = ({ filesList = [], maxFileSize = 2, maxFileCount = 10, acceptedFormats = {
|
|
6
|
+
export const FileAttach = ({ filesList = [], maxFileSize = 2, maxFileCount = 10, maxFileName = 0, acceptedFormats = {
|
|
7
7
|
'image/*': ['.png', '.gif', '.jpeg', '.jpg'],
|
|
8
8
|
'application/pdf': ['.pdf'],
|
|
9
9
|
'application/msword': ['.doc', '.docx'],
|
|
10
|
+
'model/gltf-binary': ['.glb'],
|
|
11
|
+
'application/octet-stream': ['.prt', '.step', '.stp'],
|
|
12
|
+
'text/plain': ['.syslog'],
|
|
10
13
|
}, addedFiles, setAddedFiles, onDownload, onDelete, canAdd = true, canDelete = true, canDownload = true, position = 'bottom', lng = 'ru', className, style, fileValidator, }) => {
|
|
11
14
|
const fileAttachClasses = classNames(styles['fileAttach'], className, {
|
|
12
15
|
[styles[`fileAttach_position_${position}`]]: position,
|
|
13
16
|
});
|
|
14
17
|
return (React.createElement("div", { className: fileAttachClasses, style: style },
|
|
15
|
-
React.createElement(FileLoader, { maxFileSize: maxFileSize, maxFileCount: maxFileCount, acceptedFormats: acceptedFormats, addedFiles: addedFiles, setAddedFiles: setAddedFiles, filesList: filesList, canAdd: canAdd, lng: lng, fileValidator: fileValidator }),
|
|
18
|
+
React.createElement(FileLoader, { maxFileSize: maxFileSize, maxFileCount: maxFileCount, maxFileName: maxFileName, acceptedFormats: acceptedFormats, addedFiles: addedFiles, setAddedFiles: setAddedFiles, filesList: filesList, canAdd: canAdd, lng: lng, fileValidator: fileValidator }),
|
|
16
19
|
React.createElement(FileListAttaсhed, { filesList: filesList, onDelete: onDelete, onDownload: onDownload, canDelete: canDelete, canDownload: canDownload, lng: lng })));
|
|
17
20
|
};
|
|
@@ -7,7 +7,7 @@ import { IconClose, IconDownload, IconFile } from '../../Icons';
|
|
|
7
7
|
import { Tooltip } from '../Tooltip/Tooltip';
|
|
8
8
|
import classNames from 'classnames';
|
|
9
9
|
import { formatFileSize } from '../AttachedFilesPreview/AttachedFilesPreview';
|
|
10
|
-
export const FileItem = ({ file, loading = false, error = '', onDownload, onDelete, canDelete = true, canDownload = true, style, isAddedFile, isRejectedFile, progressBarWidth }) => {
|
|
10
|
+
export const FileItem = ({ file, loading = false, error = '', onDownload, onDelete, canDelete = true, canDownload = true, style, isAddedFile, isRejectedFile, progressBarWidth, lng }) => {
|
|
11
11
|
const [isLoadingFinished, setIsLoadingFinished] = useState(false);
|
|
12
12
|
const [animationDuration, setAnimationDuration] = useState(0);
|
|
13
13
|
const [maxLength, setMaxLength] = useState(30);
|
|
@@ -103,7 +103,7 @@ export const FileItem = ({ file, loading = false, error = '', onDownload, onDele
|
|
|
103
103
|
React.createElement("div", { className: styles['fileItemName'], ref: fileNameRef },
|
|
104
104
|
file.filename.length > maxLength ? (React.createElement(Tooltip, { label: file.filename, position: "bottom-center", displayDelay: 300 },
|
|
105
105
|
React.createElement(Typography, { variant: "Body1", color: "var(--text-dark)" }, croppedName(file.filename)))) : (React.createElement(Typography, { variant: "Body1", color: "var(--text-dark)" }, croppedName(file.filename))),
|
|
106
|
-
file.size !== 0 && (React.createElement(Typography, { variant: "Caption", color: "var(--grey-medium)" }, formatFileSize(file.size))))),
|
|
106
|
+
file.size !== 0 && (React.createElement(Typography, { variant: "Caption", color: "var(--grey-medium)" }, formatFileSize(file.size, lng))))),
|
|
107
107
|
React.createElement("div", { className: styles['fileItemActions'] },
|
|
108
108
|
!(isAddedFile || isRejectedFile) && canDownload && (React.createElement(IconButton, { className: styles.fileIcon, icon: React.createElement(IconDownload, null), onClick: (e) => handleDownloadClick(e, file), color: "var(--icons-grey)", size: "sm" })),
|
|
109
109
|
canDelete && (React.createElement(IconButton, { className: styles.fileIcon, icon: React.createElement(IconClose, null), onClick: (e) => handleDeleteClick(e, file.id || ''), color: "var(--icons-grey)", size: "sm" })))),
|
|
@@ -10,5 +10,5 @@ export const FileListAttaсhed = ({ filesList, onDelete, onDownload, canDelete,
|
|
|
10
10
|
return (React.createElement("div", { className: classNames(styles['fileList'], className), style: style },
|
|
11
11
|
isInfoShown &&
|
|
12
12
|
(lng === 'ru' || lng.includes('ru') ? (React.createElement(Typography, { variant: "Body2-SemiBold", color: "var(--text-dark)", style: { lineHeight: '20px' }, className: styles['fileListHeader'] }, `Прикрепленные файлы (${filesList.length})`)) : (React.createElement(Typography, { variant: "Body2-SemiBold", color: "var(--text-dark)", style: { lineHeight: '20px' }, className: styles['fileListHeader'] }, `Attached files (${filesList.length})`))),
|
|
13
|
-
React.createElement("div", { className: styles['fileListFiles'] }, filesList.map((file) => (React.createElement(FileItem, { key: file.id, file: file, onDownload: onDownload, onDelete: onDelete, canDelete: canDelete, canDownload: canDownload }))))));
|
|
13
|
+
React.createElement("div", { className: styles['fileListFiles'] }, filesList.map((file) => (React.createElement(FileItem, { key: file.id, file: file, onDownload: onDownload, onDelete: onDelete, canDelete: canDelete, canDownload: canDownload, lng: lng }))))));
|
|
14
14
|
};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { FileLoaderProps } from '../../types';
|
|
3
|
-
export declare const FileLoader:
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { FileLoaderHandle, FileLoaderProps } from '../../types';
|
|
3
|
+
export declare const FileLoader: React.ForwardRefExoticComponent<FileLoaderProps & React.RefAttributes<FileLoaderHandle>>;
|
|
@@ -1,23 +1,34 @@
|
|
|
1
|
-
import React, { useEffect, useState } from 'react';
|
|
1
|
+
import React, { forwardRef, useEffect, useImperativeHandle, useState } from 'react';
|
|
2
2
|
import { useDropzone } from 'react-dropzone';
|
|
3
3
|
import styles from './FileLoader.module.css';
|
|
4
4
|
import { Typography } from '../Typography/Typography';
|
|
5
5
|
import { IconUpload } from '../../Icons';
|
|
6
6
|
import { FileItem } from '../FileItem/FileItem';
|
|
7
7
|
import classNames from 'classnames';
|
|
8
|
-
export const FileLoader = ({ maxFileSize = 2, maxFileCount = 10, acceptedFormats = {
|
|
8
|
+
export const FileLoader = forwardRef(({ maxFileSize = 2, maxFileCount = 10, maxFileName = 0, acceptedFormats = {
|
|
9
9
|
'image/*': ['.png', '.gif', '.jpeg', '.jpg'],
|
|
10
10
|
'application/pdf': ['.pdf'],
|
|
11
|
-
'application/msword': ['.doc', '.docx'],
|
|
12
|
-
}, addedFiles, setAddedFiles, filesList = [], canAdd = true, lng = 'ru', className, style, fileValidator, progressBarWidth }) => {
|
|
11
|
+
'application/msword': ['.doc', '.docx', '.log', '.syslog', '.txt'],
|
|
12
|
+
}, rejectedFormats, addedFiles, setAddedFiles, filesList = [], canAdd = true, lng = 'ru', className, style, fileValidator, progressBarWidth }, ref) => {
|
|
13
13
|
const [isLoadingFiles, setIsLoadingFiles] = useState(false);
|
|
14
14
|
const [loadingFilesNames, setLoadingFilesNames] = useState([]);
|
|
15
15
|
const [errorFiles, setErrorFiles] = useState([]);
|
|
16
16
|
const [addedFilesFormated, setAddedFilesFormatted] = useState([]);
|
|
17
|
+
useImperativeHandle(ref, () => ({
|
|
18
|
+
clearErrorFiles: () => {
|
|
19
|
+
setErrorFiles([]);
|
|
20
|
+
},
|
|
21
|
+
clearAllFiles: () => {
|
|
22
|
+
setErrorFiles([]);
|
|
23
|
+
setAddedFiles([]);
|
|
24
|
+
setAddedFilesFormatted([]);
|
|
25
|
+
setLoadingFilesNames([]);
|
|
26
|
+
}
|
|
27
|
+
}));
|
|
17
28
|
const fileValidatorInner = (file) => {
|
|
18
29
|
if (file.size > maxFileSize * 1024 * 1024 * 1024) {
|
|
19
30
|
return {
|
|
20
|
-
code: '
|
|
31
|
+
code: 'size-too-large',
|
|
21
32
|
message: lng === 'ru' || lng.includes('ru')
|
|
22
33
|
? `Максимальный размер файла ${maxFileSize.toFixed(0)} ГБ`
|
|
23
34
|
: `Maximum file size ${maxFileSize.toFixed(0)} GB`,
|
|
@@ -43,7 +54,13 @@ export const FileLoader = ({ maxFileSize = 2, maxFileCount = 10, acceptedFormats
|
|
|
43
54
|
message: lng === 'ru' || lng.includes('ru') ? `Максимальное количество файлов ${maxFileCount}` : `Maximum number of files ${maxFileCount}`,
|
|
44
55
|
};
|
|
45
56
|
}
|
|
46
|
-
if (
|
|
57
|
+
if (maxFileName && file.name.length > maxFileName) {
|
|
58
|
+
return {
|
|
59
|
+
code: 'name-too-large',
|
|
60
|
+
message: lng === 'ru' || lng.includes('ru') ? `Имя файла не может превышать ${maxFileName} символов` : `File name must be under ${maxFileName} symbols`,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
if (acceptedFormats && !rejectedFormats) {
|
|
47
64
|
const acceptedExtensions = Object.values(acceptedFormats)
|
|
48
65
|
.reduce((acc, val) => acc.concat(val), []);
|
|
49
66
|
const fileParts = file.name.split('.');
|
|
@@ -59,6 +76,22 @@ export const FileLoader = ({ maxFileSize = 2, maxFileCount = 10, acceptedFormats
|
|
|
59
76
|
};
|
|
60
77
|
}
|
|
61
78
|
}
|
|
79
|
+
if (rejectedFormats) {
|
|
80
|
+
const rejectedExtensions = Object.values(rejectedFormats)
|
|
81
|
+
.reduce((acc, val) => acc.concat(val), []);
|
|
82
|
+
const fileParts = file.name.split('.');
|
|
83
|
+
const fileExtension = fileParts.length > 1
|
|
84
|
+
? `.${fileParts.pop().toLowerCase()}`
|
|
85
|
+
: '';
|
|
86
|
+
if (rejectedExtensions.includes(fileExtension)) {
|
|
87
|
+
return {
|
|
88
|
+
code: 'file-invalid-type',
|
|
89
|
+
message: lng === 'ru' || lng.includes('ru')
|
|
90
|
+
? `Файл не должен быть одного из следующих типов: ${getAcceptedFormatsString(rejectedFormats)}`
|
|
91
|
+
: `File must not be one of: ${getAcceptedFormatsString(rejectedFormats)}`,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
}
|
|
62
95
|
if (fileValidator) {
|
|
63
96
|
const customValidationResult = fileValidator(file);
|
|
64
97
|
if (customValidationResult) {
|
|
@@ -141,21 +174,23 @@ export const FileLoader = ({ maxFileSize = 2, maxFileCount = 10, acceptedFormats
|
|
|
141
174
|
setLoadingFilesNames(loadingFilesNames.filter((id) => id !== id));
|
|
142
175
|
};
|
|
143
176
|
const acceptedFileItems = addedFilesFormated.map((file) => {
|
|
144
|
-
return (React.createElement(FileItem, { key: file.id, file: file, loading: loadingFilesNames.includes(file.filename), onDelete: handleDeleteFiles, isAddedFile: true, progressBarWidth: progressBarWidth }));
|
|
177
|
+
return (React.createElement(FileItem, { key: file.id, file: file, loading: loadingFilesNames.includes(file.filename), onDelete: handleDeleteFiles, isAddedFile: true, progressBarWidth: progressBarWidth, lng: lng }));
|
|
145
178
|
});
|
|
146
179
|
const handleDeleteRejectedFile = (id) => {
|
|
147
180
|
setErrorFiles(errorFiles.filter((rejection) => rejection.file.id !== id));
|
|
148
181
|
};
|
|
149
|
-
const fileRejectionItems = errorFiles.map(({ file, errors }) => (React.createElement(FileItem, { key: file.id, file: file, error: errors[0].message, onDelete: handleDeleteRejectedFile, isRejectedFile: true })));
|
|
182
|
+
const fileRejectionItems = errorFiles.map(({ file, errors }) => (React.createElement(FileItem, { key: file.id, file: file, error: errors[0].message, onDelete: handleDeleteRejectedFile, isRejectedFile: true, lng: lng })));
|
|
150
183
|
// Функция для получения всех доступных форматов в виде строки
|
|
151
184
|
const getAcceptedFormatsString = (acceptedFormats) => {
|
|
152
|
-
const
|
|
185
|
+
const uniqueFormats = new Set();
|
|
153
186
|
for (const key in acceptedFormats) {
|
|
154
187
|
if (acceptedFormats.hasOwnProperty(key)) {
|
|
155
|
-
|
|
188
|
+
acceptedFormats[key].forEach((format) => {
|
|
189
|
+
uniqueFormats.add(format.replace('.', ''));
|
|
190
|
+
});
|
|
156
191
|
}
|
|
157
192
|
}
|
|
158
|
-
return
|
|
193
|
+
return Array.from(uniqueFormats).join(', ');
|
|
159
194
|
};
|
|
160
195
|
useEffect(() => {
|
|
161
196
|
if (addedFiles.length === 0) {
|
|
@@ -189,9 +224,9 @@ export const FileLoader = ({ maxFileSize = 2, maxFileCount = 10, acceptedFormats
|
|
|
189
224
|
React.createElement("br", null)))),
|
|
190
225
|
maxFileCount &&
|
|
191
226
|
(lng === 'ru' || lng.includes('ru') ? (React.createElement(Typography, { variant: "Body2", color: "var(--grey-medium)" }, `За раз можно загрузить ${maxFileCount} ${maxFileCount > 1 ? `файлов` : `файл`}`)) : (React.createElement(Typography, { variant: "Body2", color: "var(--grey-medium)" }, `You can upload ${maxFileCount} ${maxFileCount > 1 ? `files` : `file`}`))))),
|
|
192
|
-
acceptedFormats &&
|
|
193
|
-
|
|
227
|
+
acceptedFormats && !rejectedFormats && (React.createElement(Typography, { variant: "Body2", color: "var(--grey-medium)" }, `${lng === 'ru' || lng.includes('ru') ? 'Поддерживаемые форматы:' : 'Supported formats:'} ${getAcceptedFormatsString(acceptedFormats)}`)),
|
|
228
|
+
rejectedFormats && (React.createElement(Typography, { variant: "Body2", color: "var(--grey-medium)" }, `${lng === 'ru' || lng.includes('ru') ? 'Неподдерживаемые форматы:' : 'Unsupported formats:'} ${getAcceptedFormatsString(rejectedFormats)}`)),
|
|
194
229
|
(addedFiles === null || addedFiles === void 0 ? void 0 : addedFiles.length) > 0 || (errorFiles === null || errorFiles === void 0 ? void 0 : errorFiles.length) > 0 ? (React.createElement("div", { className: styles['addedFiles'] },
|
|
195
230
|
acceptedFileItems,
|
|
196
231
|
fileRejectionItems)) : lng === 'ru' || lng.includes('ru') ? (React.createElement(Typography, { variant: "Body2-SemiBold", color: "var(--grey-medium)", style: { marginTop: '5px' } }, "\u0424\u0430\u0439\u043B\u044B \u043D\u0435 \u0434\u043E\u0431\u0430\u0432\u043B\u0435\u043D\u044B")) : (React.createElement(Typography, { variant: "Body2-SemiBold", color: "var(--grey-medium)", style: { marginTop: '5px' } }, "Files not added"))));
|
|
197
|
-
};
|
|
232
|
+
});
|
|
@@ -23,7 +23,7 @@ const getElementFromRange = (range) => {
|
|
|
23
23
|
const container = range.commonAncestorContainer;
|
|
24
24
|
return container.nodeType === Node.TEXT_NODE ? container.parentElement : container;
|
|
25
25
|
};
|
|
26
|
-
export const TextEditor = ({ label, onSubmit, onChange, defaultValue, error, helperText, canAttachFiles = false, files, required, className, isButtonDisabled, }) => {
|
|
26
|
+
export const TextEditor = ({ label, onSubmit, onChange, defaultValue, error, helperText, canAttachFiles = false, files, required, className, isButtonDisabled, lng = 'ru', }) => {
|
|
27
27
|
const editorRef = useRef(null);
|
|
28
28
|
const uploaderRef = useRef(null);
|
|
29
29
|
const submitButtonRef = useRef(null);
|
|
@@ -293,6 +293,7 @@ export const TextEditor = ({ label, onSubmit, onChange, defaultValue, error, hel
|
|
|
293
293
|
file,
|
|
294
294
|
id: `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
|
|
295
295
|
preview: file.type.startsWith('image/') ? URL.createObjectURL(file) : undefined,
|
|
296
|
+
lng,
|
|
296
297
|
}));
|
|
297
298
|
setAttachedFiles((prev) => [...prev, ...newAttachedFiles]);
|
|
298
299
|
event.target.value = '';
|
|
@@ -535,7 +536,7 @@ export const TextEditor = ({ label, onSubmit, onChange, defaultValue, error, hel
|
|
|
535
536
|
return (React.createElement("div", { className: wrapperClassess },
|
|
536
537
|
label && (React.createElement(Typography, { variant: "Caption", className: labelClasses }, label)),
|
|
537
538
|
React.createElement("div", { className: inputClassess },
|
|
538
|
-
attachedFiles.length > 0 && (React.createElement(AttachedFilesPreview, { files: attachedFiles, onDelete: (id) => removeAttachedFile(id), className: styles.attachedFilesContainer, isEdit: true })),
|
|
539
|
+
attachedFiles.length > 0 && (React.createElement(AttachedFilesPreview, { files: attachedFiles, onDelete: (id) => removeAttachedFile(id), className: styles.attachedFilesContainer, isEdit: true, lng: lng })),
|
|
539
540
|
React.createElement("div", { ref: editorRef }),
|
|
540
541
|
canAttachFiles && (React.createElement("input", { ref: uploaderRef, type: "file", style: { display: 'none' }, multiple: true, onChange: handleUploadFiles, accept: ACCEPTED_FILE_TYPES }))),
|
|
541
542
|
error && helperText && (React.createElement(Typography, { variant: "Caption", className: classNames(styles.helperText) }, helperText))));
|
package/dist/types/index.d.ts
CHANGED
|
@@ -186,6 +186,10 @@ export interface DropdownProps {
|
|
|
186
186
|
defaultValue?: string | number | TOptions | null;
|
|
187
187
|
/** Callback, который будет вызван при изменении значения */
|
|
188
188
|
onChange?: (event: any, value: string | number | TOptions | null) => void;
|
|
189
|
+
/** Флаг, является ли выпадающий список пагинированным */
|
|
190
|
+
showLoadMore?: boolean;
|
|
191
|
+
/** Функция для загрузки списка при пагинированных данных */
|
|
192
|
+
loadMore?: () => void;
|
|
189
193
|
/** Функция для получения текста опции */
|
|
190
194
|
getOptionLabel?: (option: TOptions) => string;
|
|
191
195
|
/** Вариaнты выпадающего списка(текст + иконка, текст)' */
|
|
@@ -383,6 +387,8 @@ export interface FileAttachProps {
|
|
|
383
387
|
maxFileSize?: number;
|
|
384
388
|
/** Максимальное количество файлов */
|
|
385
389
|
maxFileCount?: number;
|
|
390
|
+
/** Максимальное количество символов в названии файла */
|
|
391
|
+
maxFileName?: number;
|
|
386
392
|
/**Поддерживаемые форматы файлов */
|
|
387
393
|
acceptedFormats?: Accept;
|
|
388
394
|
/**Добавленные файлы */
|
|
@@ -453,14 +459,20 @@ export interface FileItemProps {
|
|
|
453
459
|
isRejectedFile?: boolean;
|
|
454
460
|
/** Ширина прогресс бара */
|
|
455
461
|
progressBarWidth?: string;
|
|
462
|
+
/** Язык интерфейса для типов данных*/
|
|
463
|
+
lng?: string;
|
|
456
464
|
}
|
|
457
465
|
export interface FileLoaderProps {
|
|
458
466
|
/** Максимальный размер файла */
|
|
459
467
|
maxFileSize?: number;
|
|
460
468
|
/** Максимальное количество файлов */
|
|
461
469
|
maxFileCount?: number;
|
|
470
|
+
/** Максимальное количество символов в названии файла */
|
|
471
|
+
maxFileName?: number;
|
|
462
472
|
/**Поддерживаемые форматы файлов */
|
|
463
473
|
acceptedFormats?: Accept;
|
|
474
|
+
/** Неподдерживаемые форматы файлов */
|
|
475
|
+
rejectedFormats?: Accept;
|
|
464
476
|
/**Добавленные файлы */
|
|
465
477
|
addedFiles: File[];
|
|
466
478
|
/**Сосотояние для добавления файлов */
|
|
@@ -480,6 +492,10 @@ export interface FileLoaderProps {
|
|
|
480
492
|
/** Ширина прогресс бара */
|
|
481
493
|
progressBarWidth?: string;
|
|
482
494
|
}
|
|
495
|
+
export interface FileLoaderHandle {
|
|
496
|
+
clearErrorFiles: () => void;
|
|
497
|
+
clearAllFiles: () => void;
|
|
498
|
+
}
|
|
483
499
|
export interface DialogProps {
|
|
484
500
|
/** Флаг открытия окна */
|
|
485
501
|
open: boolean;
|
|
@@ -606,6 +622,8 @@ export interface TextEditorProps {
|
|
|
606
622
|
required?: boolean;
|
|
607
623
|
className?: string;
|
|
608
624
|
isButtonDisabled?: boolean;
|
|
625
|
+
/** Язык */
|
|
626
|
+
lng?: string;
|
|
609
627
|
}
|
|
610
628
|
export interface CommentProps {
|
|
611
629
|
/** Идентификатор элемента */
|
|
@@ -635,6 +653,8 @@ export interface CommentProps {
|
|
|
635
653
|
onChange?: (value: string, files: FilePreview[]) => void;
|
|
636
654
|
onSubmit?: (value: string, files: FilePreview[]) => void;
|
|
637
655
|
onDelete?: (id: string) => void;
|
|
656
|
+
/** Язык */
|
|
657
|
+
lng?: string;
|
|
638
658
|
}
|
|
639
659
|
export interface LinkProps {
|
|
640
660
|
/**Гипертекстовая ссылка */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kamotive_ui",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "8.12.25",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"files": [
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"react": "^18.3.1",
|
|
28
28
|
"react-datepicker": "^8.2.1",
|
|
29
29
|
"react-dom": "^18.3.1",
|
|
30
|
-
"react-dropzone": "^14.3.
|
|
30
|
+
"react-dropzone": "^14.3.8"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@chromatic-com/storybook": "^3.2.2",
|