kamotive_ui 2.3.26 → 3.6.26

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 (70) hide show
  1. package/dist/components/AttachedFilesPreview/AttachedFilesPreview.d.ts +1 -0
  2. package/dist/components/AttachedFilesPreview/AttachedFilesPreview.js +4 -4
  3. package/dist/components/Breadcrumb/Breadcrumb.js +4 -4
  4. package/dist/components/Breadcrumbs/Breadcrumbs.js +10 -4
  5. package/dist/components/Button/Button.d.ts +1 -1
  6. package/dist/components/Button/Button.js +11 -10
  7. package/dist/components/Button/Button.module.css +2 -1
  8. package/dist/components/Checkbox/Checkbox.js +4 -4
  9. package/dist/components/ColorPicker/ColorPicker.js +9 -8
  10. package/dist/components/Comment/Comment.js +13 -13
  11. package/dist/components/DateInput/DateInput.js +20 -19
  12. package/dist/components/Dialog/Dialog.js +5 -5
  13. package/dist/components/Dropdown/Dropdown.d.ts +3 -2
  14. package/dist/components/Dropdown/Dropdown.js +142 -53
  15. package/dist/components/Dropdown/Dropdown.module.css +25 -4
  16. package/dist/components/FileAttach/FileAttach.js +4 -4
  17. package/dist/components/FileItem/FileItem.js +8 -8
  18. package/dist/components/FileListAttached/FileListAtta/321/201hed.js +5 -5
  19. package/dist/components/FileLoader/FileLoader.js +119 -119
  20. package/dist/components/IconButton/IconButton.js +5 -2
  21. package/dist/components/Input/Input.js +6 -6
  22. package/dist/components/Link/Link.js +5 -5
  23. package/dist/components/List/List.js +13 -11
  24. package/dist/components/ListItem/ListItem.js +8 -8
  25. package/dist/components/ProgressBar/ProgressBar.js +4 -4
  26. package/dist/components/ProgressLoader/ProgressLoader.js +4 -4
  27. package/dist/components/RadioButton/RadioButton.js +4 -4
  28. package/dist/components/SettingTag/SettingTag.js +4 -4
  29. package/dist/components/Snackbar/Snackbar.js +7 -7
  30. package/dist/components/Spinner/Spinner.js +3 -3
  31. package/dist/components/Tab/Tab.js +3 -3
  32. package/dist/components/TableFilterSidebar/TableFilterSidebar.js +11 -11
  33. package/dist/components/Tabs/Tabs.js +14 -8
  34. package/dist/components/Tag/Tag.js +7 -7
  35. package/dist/components/TextEditor/TextEditor.js +179 -578
  36. package/dist/components/TextEditor/TextEditor.module.css +8 -7
  37. package/dist/components/ToggleButton/ToggleButton.js +4 -4
  38. package/dist/components/Tooltip/Tooltip.js +4 -4
  39. package/dist/components/Typography/Typography.js +2 -2
  40. package/dist/fonts/Montserrat-Bold.woff2 +0 -0
  41. package/dist/fonts/Montserrat-Italic.woff2 +0 -0
  42. package/dist/fonts/Montserrat-Light.woff2 +0 -0
  43. package/dist/fonts/Montserrat-Medium.woff2 +0 -0
  44. package/dist/fonts/Montserrat-MediumItalic.woff2 +0 -0
  45. package/dist/fonts/Montserrat-Regular.woff2 +0 -0
  46. package/dist/fonts/Montserrat-SemiBold.woff2 +0 -0
  47. package/dist/fonts/Montserrat-SemiBoldItalic.woff2 +0 -0
  48. package/dist/fonts/OpenSans-Bold.woff2 +0 -0
  49. package/dist/fonts/OpenSans-BoldItalic.woff2 +0 -0
  50. package/dist/fonts/OpenSans-Italic.woff2 +0 -0
  51. package/dist/fonts/OpenSans-Italic_1.woff2 +0 -0
  52. package/dist/fonts/OpenSans-Light.woff2 +0 -0
  53. package/dist/fonts/OpenSans-LightItalic.woff2 +0 -0
  54. package/dist/fonts/OpenSans-Medium.woff2 +0 -0
  55. package/dist/fonts/OpenSans-MediumItalic.woff2 +0 -0
  56. package/dist/fonts/OpenSans-Regular.woff2 +0 -0
  57. package/dist/fonts/OpenSans-Regular_1.woff2 +0 -0
  58. package/dist/fonts/OpenSans-SemiBold.woff2 +0 -0
  59. package/dist/fonts/OpenSans-SemiBoldItalic.woff2 +0 -0
  60. package/dist/fonts.scss +144 -0
  61. package/dist/index.d.ts +0 -2
  62. package/dist/index.js +0 -2
  63. package/dist/types/global.d.ts +26 -0
  64. package/dist/types/index.d.ts +56 -14
  65. package/dist/types/pell.d.ts +29 -0
  66. package/dist/{colors.css → variables.scss} +34 -0
  67. package/package.json +6 -1
  68. package/dist/components/Checkbox/Checkbox.stories.d.ts +0 -66
  69. package/dist/components/Checkbox/Checkbox.stories.js +0 -75
  70. package/dist/fonts.css +0 -37
@@ -5,11 +5,105 @@ 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
+ const getFileNameWithoutExtension = (filename) => {
9
+ const lastDotIndex = filename.lastIndexOf('.');
10
+ if (lastDotIndex === -1 || lastDotIndex === 0 || lastDotIndex === filename.length - 1) {
11
+ return filename;
12
+ }
13
+ return filename.substring(0, lastDotIndex);
14
+ };
15
+ const getFileExtension = (filename) => {
16
+ const lastDotIndex = filename.lastIndexOf('.');
17
+ if (lastDotIndex === -1 || lastDotIndex === filename.length - 1) {
18
+ return '';
19
+ }
20
+ return filename.substring(lastDotIndex).toLowerCase();
21
+ };
22
+ // Функция для получения всех доступных форматов в виде строки
23
+ const getAcceptedFormatsString = (acceptedFormats) => {
24
+ const uniqueFormats = new Set();
25
+ for (const key in acceptedFormats) {
26
+ if (acceptedFormats.hasOwnProperty(key)) {
27
+ acceptedFormats[key].forEach((format) => {
28
+ uniqueFormats.add(format.replace('.', ''));
29
+ });
30
+ }
31
+ }
32
+ return Array.from(uniqueFormats).join(', ');
33
+ };
34
+ const fileValidatorInner = (file, maxFileSize, maxFileCount, maxFileName, addedFilesLength, lng, acceptedFormats, rejectedFormats, fileValidator) => {
35
+ const fileExtension = getFileExtension(file.name);
36
+ const fileNameWithoutExt = getFileNameWithoutExtension(file.name);
37
+ const nameLength = Array.from(fileNameWithoutExt).length;
38
+ const fileParts = file.name.split('.');
39
+ const fileExt = fileParts.length > 1 ? `.${fileParts.pop().toLowerCase()}` : '';
40
+ const checks = {
41
+ isSizeTooLarge: file.size > maxFileSize * 1024 * 1024 * 1024,
42
+ isTooManyFiles: addedFilesLength > maxFileCount - 1,
43
+ isNameTooLarge: typeof maxFileName === 'number' && maxFileName > 0 && nameLength > maxFileName,
44
+ isAcceptedFormatValid: true,
45
+ isRejectedFormatValid: true
46
+ };
47
+ // Проверка форматов
48
+ if (acceptedFormats && !rejectedFormats) {
49
+ const acceptedExtensions = Object.values(acceptedFormats).reduce((acc, val) => acc.concat(val), []);
50
+ checks.isAcceptedFormatValid = acceptedExtensions.includes(fileExtension);
51
+ }
52
+ if (rejectedFormats) {
53
+ const rejectedExtensions = Object.values(rejectedFormats).reduce((acc, val) => acc.concat(val), []);
54
+ checks.isRejectedFormatValid = !rejectedExtensions.includes(fileExt);
55
+ }
56
+ switch (true) {
57
+ case checks.isSizeTooLarge:
58
+ return {
59
+ code: 'size-too-large',
60
+ message: lng === 'ru' || lng.includes('ru')
61
+ ? `Максимальный размер файла ${maxFileSize.toFixed(0)} ГБ`
62
+ : `Maximum file size ${maxFileSize.toFixed(0)} GB`,
63
+ };
64
+ case checks.isTooManyFiles:
65
+ return {
66
+ code: 'files-count-too-large',
67
+ message: lng === 'ru' || lng.includes('ru')
68
+ ? `Максимальное количество файлов ${maxFileCount}`
69
+ : `Maximum number of files ${maxFileCount}`,
70
+ };
71
+ case checks.isNameTooLarge:
72
+ return {
73
+ code: 'name-too-large',
74
+ message: lng === 'ru' || lng.includes('ru')
75
+ ? `Имя файла не может превышать ${maxFileName} символов.`
76
+ : `File name must be under ${maxFileName} symbols.`,
77
+ };
78
+ case !checks.isAcceptedFormatValid:
79
+ return {
80
+ code: 'file-invalid-type',
81
+ message: lng === 'ru' || lng.includes('ru')
82
+ ? `Файл должен быть одного из следующих типов: ${Object.values(acceptedFormats).reduce((acc, val) => acc.concat(val), []).join(', ')}`
83
+ : `File must be one of: ${Object.values(acceptedFormats).reduce((acc, val) => acc.concat(val), []).join(', ')}`,
84
+ };
85
+ case !checks.isRejectedFormatValid:
86
+ return {
87
+ code: 'file-invalid-type',
88
+ message: lng === 'ru' || lng.includes('ru')
89
+ ? `Файл не должен быть одного из следующих типов: ${getAcceptedFormatsString(rejectedFormats)}`
90
+ : `File must not be one of: ${getAcceptedFormatsString(rejectedFormats)}`,
91
+ };
92
+ default: {
93
+ if (fileValidator) {
94
+ const customValidationResult = fileValidator(file);
95
+ if (customValidationResult)
96
+ return customValidationResult;
97
+ }
98
+ return null;
99
+ }
100
+ }
101
+ };
8
102
  export const FileLoader = forwardRef(({ maxFileSize = 2, maxFileCount = 10, maxFileName = 0, acceptedFormats = {
9
103
  'image/*': ['.png', '.gif', '.jpeg', '.jpg'],
10
104
  'application/pdf': ['.pdf'],
11
105
  'application/msword': ['.doc', '.docx', '.log', '.syslog', '.txt'],
12
- }, rejectedFormats, addedFiles, setAddedFiles, canAdd = true, lng = 'ru', className, style, fileValidator }, ref) => {
106
+ }, rejectedFormats, addedFiles, setAddedFiles, canAdd = true, lng = 'ru', className, style, fileValidator, testId = 'default' }, ref) => {
13
107
  const [isLoadingFiles, setIsLoadingFiles] = useState(false);
14
108
  const [loadingFilesNames, setLoadingFilesNames] = useState([]);
15
109
  const [errorFiles, setErrorFiles] = useState([]);
@@ -25,92 +119,15 @@ export const FileLoader = forwardRef(({ maxFileSize = 2, maxFileCount = 10, maxF
25
119
  setLoadingFilesNames([]);
26
120
  }
27
121
  }));
28
- const fileValidatorInner = (file) => {
29
- if (file.size > maxFileSize * 1024 * 1024 * 1024) {
30
- return {
31
- code: 'size-too-large',
32
- message: lng === 'ru' || lng.includes('ru')
33
- ? `Максимальный размер файла ${maxFileSize.toFixed(0)} ГБ`
34
- : `Maximum file size ${maxFileSize.toFixed(0)} GB`,
35
- };
36
- }
37
- // Проверка на дубликаты в filesList
38
- // if (filesList.find((existingFile: TAttachments) => existingFile.filename === file.name)) {
39
- // return {
40
- // code: 'repeating-file-name',
41
- // message: lng === 'ru' || lng.includes('ru') ? `Файл уже существует в списке прикрепленных файлов` : `File already exists in the list of attached files`,
42
- // };
43
- // }
44
- // Проверка на дубликаты в addedFiles
45
- // if (addedFiles.find((addedFile: File) => addedFile.name === file.name)) {
46
- // return {
47
- // code: 'repeating-file-name',
48
- // message: lng === 'ru' || lng.includes('ru') ? `Файл уже добавлен` : `File already added`,
49
- // };
50
- // }
51
- if (addedFiles.length > maxFileCount - 1) {
52
- return {
53
- code: 'files-count-too-large',
54
- message: lng === 'ru' || lng.includes('ru') ? `Максимальное количество файлов ${maxFileCount}` : `Maximum number of files ${maxFileCount}`,
55
- };
56
- }
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) {
64
- const acceptedExtensions = Object.values(acceptedFormats)
65
- .reduce((acc, val) => acc.concat(val), []);
66
- const fileParts = file.name.split('.');
67
- const fileExtension = fileParts.length > 1
68
- ? `.${fileParts.pop().toLowerCase()}`
69
- : '';
70
- if (!acceptedExtensions.includes(fileExtension)) {
71
- return {
72
- code: 'file-invalid-type',
73
- message: lng === 'ru' || lng.includes('ru')
74
- ? `Файл должен быть одного из следующих типов: ${acceptedExtensions.join(', ')}`
75
- : `File must be one of: ${acceptedExtensions.join(', ')}`,
76
- };
77
- }
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
- }
95
- if (fileValidator) {
96
- const customValidationResult = fileValidator(file);
97
- if (customValidationResult) {
98
- return customValidationResult;
99
- }
100
- }
101
- return null;
102
- };
103
122
  const { getRootProps, getInputProps } = useDropzone({
104
123
  onDrop: (acceptedFiles, fileRejections) => {
105
124
  setAddedFiles([...addedFiles, ...acceptedFiles]);
106
- const newFormatAttachments = acceptedFiles.map((file) => {
107
- return {
108
- id: `file-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`,
109
- filename: file.name,
110
- size: file.size,
111
- type: file.type,
112
- };
113
- });
125
+ const newFormatAttachments = acceptedFiles.map((file) => ({
126
+ id: `file-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`,
127
+ filename: file.name,
128
+ size: file.size,
129
+ type: file.type,
130
+ }));
114
131
  setLoadingFilesNames(newFormatAttachments.map((file) => { var _a; return (_a = file === null || file === void 0 ? void 0 : file.filename) !== null && _a !== void 0 ? _a : 'Без названия'; }));
115
132
  setIsLoadingFiles(true);
116
133
  setAddedFilesFormatted([...addedFilesFormated, ...newFormatAttachments]);
@@ -160,7 +177,7 @@ export const FileLoader = forwardRef(({ maxFileSize = 2, maxFileCount = 10, maxF
160
177
  setErrorFiles([...errorFiles, ...formattedRejections]);
161
178
  }
162
179
  },
163
- validator: fileValidatorInner,
180
+ validator: (file) => fileValidatorInner(file, maxFileSize, maxFileCount, maxFileName, addedFiles.length, lng, acceptedFormats, rejectedFormats, fileValidator),
164
181
  accept: undefined,
165
182
  maxFiles: maxFileCount,
166
183
  disabled: !canAdd,
@@ -176,27 +193,11 @@ export const FileLoader = forwardRef(({ maxFileSize = 2, maxFileCount = 10, maxF
176
193
  setLoadingFilesNames(loadingFilesNames.filter((name) => name !== fileToDelete.filename));
177
194
  }
178
195
  };
179
- const acceptedFileItems = addedFilesFormated.map((file) => {
180
- return (React.createElement(FileItem, { key: file.id, file: file,
181
- //loading={loadingFilesNames.includes(file.filename)} // Показываем лоадер только для новых файлов
182
- onDelete: handleDeleteFiles, isAddedFile: true, lng: lng }));
183
- });
184
196
  const handleDeleteRejectedFile = (id) => {
185
197
  setErrorFiles(errorFiles.filter((rejection) => rejection.file.id !== id));
186
198
  };
187
- const fileRejectionItems = errorFiles.map(({ file, errors }) => (React.createElement(FileItem, { key: file.id, file: file, error: errors[0].message, onDelete: handleDeleteRejectedFile, isRejectedFile: true, lng: lng })));
188
- // Функция для получения всех доступных форматов в виде строки
189
- const getAcceptedFormatsString = (acceptedFormats) => {
190
- const uniqueFormats = new Set();
191
- for (const key in acceptedFormats) {
192
- if (acceptedFormats.hasOwnProperty(key)) {
193
- acceptedFormats[key].forEach((format) => {
194
- uniqueFormats.add(format.replace('.', ''));
195
- });
196
- }
197
- }
198
- return Array.from(uniqueFormats).join(', ');
199
- };
199
+ const acceptedFileItems = addedFilesFormated.map((file, index) => (React.createElement(FileItem, { key: file.id, file: file, onDelete: handleDeleteFiles, isAddedFile: true, lng: lng, testId: `${testId}-dropzone-accepted-${index}` })));
200
+ const fileRejectionItems = errorFiles.map(({ file, errors }, index) => (React.createElement(FileItem, { key: file.id, file: file, error: errors[0].message, onDelete: handleDeleteRejectedFile, isRejectedFile: true, lng: lng, testId: `${testId}-dropzone-rejected-${index}` })));
200
201
  useEffect(() => {
201
202
  if (addedFiles.length === 0) {
202
203
  setAddedFilesFormatted([]);
@@ -207,31 +208,30 @@ export const FileLoader = forwardRef(({ maxFileSize = 2, maxFileCount = 10, maxF
207
208
  setIsLoadingFiles(false);
208
209
  }
209
210
  }, [loadingFilesNames, isLoadingFiles]);
210
- return (React.createElement("section", { className: classNames(styles['fileLoader'], className), style: style },
211
- React.createElement("div", Object.assign({}, getRootProps({ className: `${styles['dropzone']} ${!canAdd ? styles['disabled'] : ''}` })),
212
- React.createElement("input", Object.assign({}, getInputProps())),
213
- React.createElement(IconUpload, { htmlColor: !canAdd ? 'var(--grey-medium)' : 'var(--icons-grey)', width: '34', height: '34' }),
214
- React.createElement(Typography, { variant: "Body1", color: !canAdd ? 'var(--grey-medium)' : 'var(--icons-grey)', style: { textAlign: 'center' } }, lng === 'ru' || lng.includes('ru') ? (React.createElement(React.Fragment, null,
211
+ return (React.createElement("section", { className: classNames(styles['fileLoader'], className), style: style, "data-test-id": `${testId}-loader-section` },
212
+ React.createElement("div", Object.assign({}, getRootProps({ className: `${styles['dropzone']} ${!canAdd ? styles['disabled'] : ''}` }), { "data-test-id": `${testId}-dropzone-block` }),
213
+ React.createElement("input", Object.assign({}, getInputProps(), { "data-test-id": `${testId}-dropzone-input`, name: 'file' })),
214
+ React.createElement("span", { "data-test-id": `${testId}-dropzone-upload-icon`, style: { display: 'inline-flex' } },
215
+ React.createElement(IconUpload, { htmlColor: !canAdd ? 'var(--grey-medium)' : 'var(--icons-grey)', width: '34', height: '34' })),
216
+ React.createElement(Typography, { variant: "Body1", color: !canAdd ? 'var(--grey-medium)' : 'var(--icons-grey)', style: { textAlign: 'center' }, testId: `${testId}-dropzone` }, lng === 'ru' || lng.includes('ru') ? (React.createElement(React.Fragment, null,
215
217
  React.createElement("span", { style: { textDecoration: 'underline' } }, "\u041D\u0430\u0436\u043C\u0438\u0442\u0435 \u043D\u0430 \u043E\u0431\u043B\u0430\u0441\u0442\u044C"),
216
- " ",
217
218
  React.createElement("span", null, " \u0438\u043B\u0438 \u043F\u0435\u0440\u0435\u0442\u0430\u0449\u0438\u0442\u0435 \u0444\u0430\u0439\u043B\u044B"))) : (React.createElement(React.Fragment, null,
218
- React.createElement("span", { style: { textDecoration: 'underline' } }, "\u0421lick on this area"),
219
- " ",
220
- React.createElement("span", null, "or drag files here")))),
219
+ React.createElement("span", { style: { textDecoration: 'underline' } }, "Click on this area"),
220
+ React.createElement("span", null, " or drag files here")))),
221
221
  React.createElement("div", null,
222
222
  maxFileSize &&
223
- (lng === 'ru' || lng.includes('ru') ? (React.createElement(Typography, { variant: "Body2", color: "var(--grey-medium)" },
223
+ (lng === 'ru' || lng.includes('ru') ? (React.createElement(Typography, { variant: "Body2", color: "var(--grey-medium)", testId: `${testId}-dropzone-sizelimits` },
224
224
  `Максимальный размер файла ${maxFileSize.toFixed(0)} ГБ`,
225
225
  " ",
226
- React.createElement("br", null))) : (React.createElement(Typography, { variant: "Body2", color: "var(--grey-medium)" },
226
+ React.createElement("br", null))) : (React.createElement(Typography, { variant: "Body2", color: "var(--grey-medium)", testId: `${testId}-dropzone-sizelimits` },
227
227
  `Maximum file size ${maxFileSize.toFixed(0)} GB`,
228
228
  " ",
229
229
  React.createElement("br", null)))),
230
230
  maxFileCount &&
231
- (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`}`))))),
232
- acceptedFormats && !rejectedFormats && (React.createElement(Typography, { variant: "Body2", color: "var(--grey-medium)" }, `${lng === 'ru' || lng.includes('ru') ? 'Поддерживаемые форматы:' : 'Supported formats:'} ${getAcceptedFormatsString(acceptedFormats)}`)),
233
- rejectedFormats && (React.createElement(Typography, { variant: "Body2", color: "var(--grey-medium)" }, `${lng === 'ru' || lng.includes('ru') ? 'Неподдерживаемые форматы:' : 'Unsupported formats:'} ${getAcceptedFormatsString(rejectedFormats)}`)),
234
- (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'] },
231
+ (lng === 'ru' || lng.includes('ru') ? (React.createElement(Typography, { variant: "Body2", color: "var(--grey-medium)", testId: `${testId}-dropzone-countlimits` }, `За раз можно загрузить ${maxFileCount} ${maxFileCount > 1 ? `файлов` : `файл`}`)) : (React.createElement(Typography, { variant: "Body2", color: "var(--grey-medium)", testId: `${testId}-dropzone-countlimits` }, `You can upload ${maxFileCount} ${maxFileCount > 1 ? `files` : `file`}`))))),
232
+ acceptedFormats && !rejectedFormats && (React.createElement(Typography, { variant: "Body2", color: "var(--grey-medium)", testId: `${testId}-dropzone-acceptformats` }, `${lng === 'ru' || lng.includes('ru') ? 'Поддерживаемые форматы:' : 'Supported formats:'} ${getAcceptedFormatsString(acceptedFormats)}`)),
233
+ rejectedFormats && (React.createElement(Typography, { variant: "Body2", color: "var(--grey-medium)", testId: `${testId}-dropzone-rejectformats` }, `${lng === 'ru' || lng.includes('ru') ? 'Неподдерживаемые форматы:' : 'Unsupported formats:'} ${getAcceptedFormatsString(rejectedFormats)}`)),
234
+ (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'], "data-test-id": `${testId}-dropzone-added-list` },
235
235
  acceptedFileItems,
236
- 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"))));
236
+ fileRejectionItems)) : (React.createElement(Typography, { variant: "Body2-SemiBold", color: "var(--grey-medium)", style: { marginTop: '5px' }, testId: `${testId}-dropzone-empty` }, lng === 'ru' || lng.includes('ru') ? 'Файлы не добавлены' : 'Files not added'))));
237
237
  });
@@ -1,7 +1,7 @@
1
1
  import React, { forwardRef } from 'react';
2
2
  import classNames from 'classnames';
3
3
  import styles from './IconButton.module.css';
4
- export const IconButton = forwardRef(({ icon, size = 'md', color, style, disabled = false, onClick, children, className, title, }, ref) => {
4
+ export const IconButton = forwardRef(({ icon, size = 'md', color, style, disabled = false, onClick, children, className, title, testId = 'default' }, ref) => {
5
5
  const validChildren = React.Children.toArray(children).filter((child) => React.isValidElement(child));
6
6
  const renderIcon = icon || validChildren[0];
7
7
  const combinedStyle = Object.assign(Object.assign(Object.assign({}, style), ((style === null || style === void 0 ? void 0 : style.backgroundColor) && {
@@ -9,7 +9,10 @@ export const IconButton = forwardRef(({ icon, size = 'md', color, style, disable
9
9
  })), ((style === null || style === void 0 ? void 0 : style.borderRadius) && {
10
10
  '--hover-border-radius': style.borderRadius,
11
11
  }));
12
- return (React.createElement("button", { ref: ref, className: classNames(styles['iconButton'], styles[`iconButton--${size}`], className), disabled: disabled, "aria-disabled": disabled, type: "button", onClick: (e) => onClick(e), style: combinedStyle, title: title }, renderIcon &&
12
+ const iconSlug = title
13
+ ? String(title).toLowerCase().trim().replace(/\s+/g, '-')
14
+ : 'action';
15
+ return (React.createElement("button", { ref: ref, className: classNames(styles['iconButton'], styles[`iconButton--${size}`], className), disabled: disabled, "aria-disabled": disabled, type: "button", onClick: (e) => onClick(e), style: combinedStyle, title: title, "data-test-id": `${testId}-${iconSlug}-button` }, renderIcon &&
13
16
  (() => {
14
17
  var _a;
15
18
  const iconElement = renderIcon;
@@ -6,7 +6,7 @@ import { Typography } from '../Typography/Typography';
6
6
  /**
7
7
  * Компонент Input для создания текстовых полей ввода различных стилей и размеров.
8
8
  */
9
- export const Input = ({ id, label, placeholder, size = 'lg', value, style, className, multiline = false, rows = 4, resize = false, disabled = false, readOnly = false, isLeftLabel = false, icon, error = false, helperText, onChange, onBlur, required = false, }) => {
9
+ export const Input = ({ id, label, placeholder, size = 'lg', value, style, className, multiline = false, rows = 4, resize = false, disabled = false, readOnly = false, isLeftLabel = false, icon, error = false, helperText, onChange, onBlur, required = false, testId = 'default' }) => {
10
10
  const [inputLabel, setInputLabel] = useState(label);
11
11
  const handleChange = (event) => {
12
12
  event.stopPropagation();
@@ -43,9 +43,9 @@ export const Input = ({ id, label, placeholder, size = 'lg', value, style, class
43
43
  [styles['label--left']]: isLeftLabel,
44
44
  [styles['label--required']]: required,
45
45
  });
46
- return (React.createElement("div", { className: wrapperClassess, style: style },
47
- inputLabel && (React.createElement(Typography, { variant: "Caption", className: labelClasses }, inputLabel)),
48
- icon && React.createElement("div", { className: styles.icon }, icon),
49
- multiline ? (React.createElement("textarea", { id: id, className: inputClassess, value: value, placeholder: placeholder, onChange: handleChange, onBlur: handleOnBlur, disabled: disabled, style: { height: `${rows * 20}px` } })) : (React.createElement("input", { id: id, className: inputClassess, value: value, placeholder: placeholder, onChange: handleChange, onBlur: handleOnBlur, disabled: disabled, readOnly: readOnly })),
50
- error && helperText && (React.createElement(Typography, { variant: "Caption", className: classNames(styles.helperText, styles[size]) }, helperText))));
46
+ return (React.createElement("div", { className: wrapperClassess, style: style, "data-test-id": `${testId}-input-block` },
47
+ inputLabel && (React.createElement(Typography, { variant: "Caption", className: labelClasses, testId: `${testId}-input` }, inputLabel)),
48
+ icon && React.createElement("div", { className: styles.icon, "data-test-id": `${testId}-input-icon` }, icon),
49
+ multiline ? (React.createElement("textarea", { id: id, name: 'textarea', className: inputClassess, value: value, placeholder: placeholder, onChange: handleChange, onBlur: handleOnBlur, disabled: disabled, style: { height: `${rows * 20}px` }, "data-test-id": `${testId}-input-textarea` })) : (React.createElement("input", { id: id, className: inputClassess, value: value, placeholder: placeholder, onChange: handleChange, onBlur: handleOnBlur, disabled: disabled, readOnly: readOnly, "data-test-id": `${testId}-input-field` })),
50
+ error && helperText && (React.createElement(Typography, { variant: "Caption", className: classNames(styles.helperText, styles[size]), testId: `${testId}-input-error` }, helperText))));
51
51
  };
@@ -4,7 +4,7 @@ import styles from './Link.module.css';
4
4
  import { Typography } from '../Typography/Typography';
5
5
  import { ETypographyVariants } from '../Typography/enums';
6
6
  import { Tooltip } from '../Tooltip/Tooltip';
7
- export const Link = ({ href, onClick, children, title, className, style, contentStyle, underline = 'hover', variant = ETypographyVariants.Body1, color = 'var(--text-dark)', maxWidth, size, widthInPixels, }) => {
7
+ export const Link = ({ href, onClick, children, title, className, style, contentStyle, underline = 'hover', variant = ETypographyVariants.Body1, color = 'var(--text-dark)', maxWidth, size, widthInPixels, testId = 'default' }) => {
8
8
  const stylesUnderline = underline === 'hover' ? styles.linkHover : underline === 'none' ? styles.linkNone : '';
9
9
  const stylesTooltipWidth = maxWidth ? { maxWidth: maxWidth } : {};
10
10
  const textRef = useRef(null);
@@ -24,8 +24,8 @@ export const Link = ({ href, onClick, children, title, className, style, content
24
24
  const shouldShow = actualSize > widthInPixels;
25
25
  return shouldShow;
26
26
  }, [actualSize, widthInPixels, size]);
27
- const linkContent = (React.createElement(Typography, { variant: variant, color: color, style: contentStyle }, children));
28
- const link = onClick ? (React.createElement("div", { onClick: onClick, className: classNames(styles.link, stylesUnderline, isTooltipVisible && styles.tooltipStyle, className), style: Object.assign(Object.assign({}, linkStyle), stylesTooltipWidth) },
27
+ const linkContent = (React.createElement(Typography, { variant: variant, color: color, style: contentStyle, testId: `${testId}-link` }, children));
28
+ const link = onClick ? (React.createElement("div", { onClick: onClick, className: classNames(styles.link, stylesUnderline, isTooltipVisible && styles.tooltipStyle, className), style: Object.assign(Object.assign({}, linkStyle), stylesTooltipWidth), "data-test-id": `${testId}-link` },
29
29
  !size && (React.createElement("div", { ref: textRef, style: {
30
30
  position: 'absolute',
31
31
  visibility: 'hidden',
@@ -34,7 +34,7 @@ export const Link = ({ href, onClick, children, title, className, style, content
34
34
  whiteSpace: 'nowrap',
35
35
  pointerEvents: 'none',
36
36
  } }, linkContent)),
37
- linkContent)) : (React.createElement("a", { href: href, title: title, className: classNames(styles.link, stylesUnderline, isTooltipVisible && styles.tooltipStyle, className), style: Object.assign(Object.assign({}, linkStyle), stylesTooltipWidth) },
37
+ linkContent)) : (React.createElement("a", { href: href, title: title, className: classNames(styles.link, stylesUnderline, isTooltipVisible && styles.tooltipStyle, className), style: Object.assign(Object.assign({}, linkStyle), stylesTooltipWidth), "data-test-id": `${testId}-link` },
38
38
  !size && (React.createElement("div", { ref: textRef, style: {
39
39
  position: 'absolute',
40
40
  visibility: 'hidden',
@@ -44,5 +44,5 @@ export const Link = ({ href, onClick, children, title, className, style, content
44
44
  pointerEvents: 'none',
45
45
  } }, linkContent)),
46
46
  linkContent));
47
- return isTooltipVisible ? (React.createElement(Tooltip, { key: `${size}-${widthInPixels}`, label: children, opacity: 0.4, displayDelay: 0, style: { maxWidth: '500px' } }, link)) : (link);
47
+ return isTooltipVisible ? (React.createElement(Tooltip, { key: `${size}-${widthInPixels}`, label: children, opacity: 0.4, displayDelay: 0, style: { maxWidth: '500px' }, testId: `${testId}-link` }, link)) : (link);
48
48
  };
@@ -6,7 +6,7 @@ import { Checkbox } from '../Checkbox/Checkbox';
6
6
  import { RadioButton } from '../RadioButton/RadioButton';
7
7
  import { ChevronDown } from '../../Icons';
8
8
  import { ListItem } from '../ListItem/ListItem';
9
- export const List = ({ onClick, onCheck, onRadioSelect, checked = false, selected = false, disabled = false, label, id, style, className, collapsible = false, open = false, withCheckbox = false, checkboxColor, checkboxFilled, withRadioButton = false, customBullet, customItemBullet, bulletClassName, titleContent, children, isHeader = false, parentChecked = false, }) => {
9
+ export const List = ({ onClick, onCheck, onRadioSelect, checked = false, selected = false, disabled = false, label, id, style, className, collapsible = false, open = false, withCheckbox = false, checkboxColor, checkboxFilled, withRadioButton = false, customBullet, customItemBullet, bulletClassName, titleContent, children, isHeader = false, parentChecked = false, testId = 'default' }) => {
10
10
  const [isOpen, setIsOpen] = useState(open);
11
11
  const [isChecked, setIsChecked] = useState(checked || parentChecked);
12
12
  const childIds = [];
@@ -57,22 +57,24 @@ export const List = ({ onClick, onCheck, onRadioSelect, checked = false, selecte
57
57
  }, [parentChecked, checked]);
58
58
  const headerClassNames = classNames(styles.header, className);
59
59
  const contentClassNames = classNames(styles.content, isOpen ? styles['content--expanded'] : styles['content--collapsed']);
60
- return (React.createElement("div", { className: styles.collapsibleList },
61
- label || titleContent && (React.createElement("div", { className: headerClassNames, onClick: handleClick, style: style },
60
+ return (React.createElement("div", { className: styles.collapsibleList, "data-test-id": `${testId}-list` },
61
+ label || titleContent && (React.createElement("div", { className: headerClassNames, onClick: handleClick, style: style, "data-test-id": `${testId}-list-header` },
62
62
  !isHeader && (React.createElement("div", null,
63
- withCheckbox && (React.createElement("span", { onClick: handleCheckboxClick },
64
- React.createElement(Checkbox, { checked: isChecked, color: checkboxColor, filled: checkboxFilled, disabled: disabled }))),
65
- withRadioButton && (React.createElement("span", { onClick: handleRadioClick },
66
- React.createElement(RadioButton, { checked: selected, value: id, disabled: disabled }))),
67
- customBullet && React.createElement("span", { className: classNames(styles.bullet, bulletClassName) }, customBullet))),
68
- label && React.createElement(Typography, { variant: "Body1" }, label),
63
+ withCheckbox && (React.createElement("span", { onClick: handleCheckboxClick, "data-test-id": `${testId}-list-chechbox-block` },
64
+ React.createElement(Checkbox, { checked: isChecked, color: checkboxColor, filled: checkboxFilled, disabled: disabled, testId: `${testId}-list` }))),
65
+ withRadioButton && (React.createElement("span", { onClick: handleRadioClick, "data-test-id": `${testId}-list-radio-block` },
66
+ React.createElement(RadioButton, { checked: selected, value: id, disabled: disabled, testId: `${testId}-list` }))),
67
+ customBullet && React.createElement("span", { className: classNames(styles.bullet, bulletClassName), "data-test-id": `${testId}-list-bullet` }, customBullet))),
68
+ label && React.createElement(Typography, { variant: "Body1", testId: `${testId}-list` }, label),
69
69
  titleContent,
70
- collapsible && (React.createElement("span", { className: styles.indicator }, isOpen ? React.createElement(ChevronDown, null) : React.createElement(ChevronDown, { rotation: 270 }))))),
71
- React.createElement("div", { className: collapsible ? contentClassNames : styles.content, style: { paddingLeft: !label ? 0 : '16px' } }, React.Children.map(children, (child) => {
70
+ collapsible && (React.createElement("span", { className: styles.indicator, "data-test-id": `${testId}-list-action-icon` }, isOpen ? React.createElement(ChevronDown, null) : React.createElement(ChevronDown, { rotation: 270 }))))),
71
+ React.createElement("div", { className: collapsible ? contentClassNames : styles.content, style: { paddingLeft: !label ? 0 : '16px' }, "data-test-id": `${testId}-list-content-block` }, React.Children.map(children, (child, index) => {
72
72
  if (React.isValidElement(child)) {
73
+ const childTestId = child.props.testId || `${testId}-list-${index}`;
73
74
  const commonProps = {
74
75
  style: child.props.style || style,
75
76
  className: child.props.className,
77
+ testId: childTestId,
76
78
  };
77
79
  if (child.type === ListItem || child.type === List) {
78
80
  return React.cloneElement(child, Object.assign(Object.assign({}, commonProps), { bulletClassName: classNames(styles.bullet, child.props.bulletClassName || bulletClassName), customBullet: child.props.customBullet !== undefined
@@ -4,7 +4,7 @@ import styles from './ListItem.module.css';
4
4
  import { Typography } from '../Typography/Typography';
5
5
  import { Checkbox } from '../Checkbox/Checkbox';
6
6
  import { RadioButton } from '../RadioButton/RadioButton';
7
- export const ListItem = ({ id, onClick, onCheck, onRadioSelect, checked = false, selected = false, disabled = false, label, style, className, withCheckbox = false, checkboxColor, checkboxFilled, withRadioButton = false, customBullet, bulletClassName, children, parentChecked, }) => {
7
+ export const ListItem = ({ id, onClick, onCheck, onRadioSelect, checked = false, selected = false, disabled = false, label, style, className, withCheckbox = false, checkboxColor, checkboxFilled, withRadioButton = false, customBullet, bulletClassName, children, parentChecked, testId = 'default' }) => {
8
8
  const [isChecked, setIsChecked] = useState(checked || parentChecked);
9
9
  const itemClassNames = classNames(className, styles.listItem);
10
10
  const handleClick = (e) => {
@@ -30,12 +30,12 @@ export const ListItem = ({ id, onClick, onCheck, onRadioSelect, checked = false,
30
30
  useEffect(() => {
31
31
  setIsChecked(parentChecked || checked);
32
32
  }, [parentChecked, checked]);
33
- return (React.createElement("div", { className: itemClassNames, style: style, onClick: handleClick },
34
- withCheckbox && (React.createElement("span", { className: styles.icon, onClick: handleCheckboxClick },
35
- React.createElement(Checkbox, { checked: isChecked, color: checkboxColor, filled: checkboxFilled, disabled: disabled }))),
36
- withRadioButton && (React.createElement("span", { className: styles.icon, onClick: handleRadioClick },
37
- React.createElement(RadioButton, { checked: selected, value: id, disabled: disabled }))),
38
- customBullet && React.createElement("span", { className: bulletClassName }, customBullet),
39
- React.createElement(Typography, { variant: "Body1" }, label),
33
+ return (React.createElement("div", { className: itemClassNames, style: style, onClick: handleClick, "data-test-id": `${testId}-item-block` },
34
+ withCheckbox && (React.createElement("span", { className: styles.icon, onClick: handleCheckboxClick, "data-test-id": `${testId}-item-checkbox-block` },
35
+ React.createElement(Checkbox, { checked: isChecked, color: checkboxColor, filled: checkboxFilled, disabled: disabled, testId: `${testId}-item` }))),
36
+ withRadioButton && (React.createElement("span", { className: styles.icon, onClick: handleRadioClick, "data-test-id": `${testId}-item-radio-block` },
37
+ React.createElement(RadioButton, { checked: selected, value: id, disabled: disabled, testId: `${testId}-item` }))),
38
+ customBullet && React.createElement("span", { className: bulletClassName, "data-test-id": `${testId}-item-bullet` }, customBullet),
39
+ React.createElement(Typography, { variant: "Body1", testId: `${testId}-item` }, label),
40
40
  children));
41
41
  };
@@ -5,7 +5,7 @@ import classNames from 'classnames';
5
5
  /**
6
6
  * Компонент ProgressBar отображает прогресс в виде заполненной полосы.
7
7
  */
8
- export const ProgressBar = ({ value = 0, max = 100, size = 'md', showValue = true, animated = false, animationDuration = 8000, setIsLoadingFinished, width, }) => {
8
+ export const ProgressBar = ({ value = 0, max = 100, size = 'md', showValue = true, animated = false, animationDuration = 8000, setIsLoadingFinished, width, testId = 'default' }) => {
9
9
  const [percent, setPercent] = useState(value);
10
10
  const validPercentage = Math.min(Math.max(value, 0), max);
11
11
  const progressBarClasses = classNames(styles['progress-bar'], styles[size], {
@@ -37,9 +37,9 @@ export const ProgressBar = ({ value = 0, max = 100, size = 'md', showValue = tru
37
37
  setPercent(validPercentage);
38
38
  }
39
39
  }, [animated, validPercentage, setIsLoadingFinished, animationDuration]);
40
- return (React.createElement("div", { className: styles['progress-bar--wrapper'] },
41
- React.createElement("progress", { id: "linear-progress", className: progressBarClasses, value: percent, max: max, style: { width: width } }),
42
- React.createElement("label", { htmlFor: "progress", className: styles['progress-bar-percentage'] }, showValue && (React.createElement(Typography, { variant: "Body1", color: '#9CA0A7', className: styles['progress-bar-percentage'] },
40
+ return (React.createElement("div", { className: styles['progress-bar--wrapper'], "data-test-id": `${testId}-progressbar` },
41
+ React.createElement("progress", { id: "linear-progress", className: progressBarClasses, value: percent, max: max, style: { width: width }, "data-test-id": `${testId}-progressbar-indicator` }),
42
+ React.createElement("label", { htmlFor: "progress", className: styles['progress-bar-percentage'], "data-test-id": `${testId}-progressbar-label` }, showValue && (React.createElement(Typography, { variant: "Body1", color: '#9CA0A7', className: styles['progress-bar-percentage'], testId: `${testId}-progressbar` },
43
43
  percent,
44
44
  "%")))));
45
45
  };
@@ -9,7 +9,7 @@ import classNames from 'classnames';
9
9
  const spinnerSizes = { xl: 89, lg: 56, md: 40, sm: 34 };
10
10
  const animationDuration = 4000; // Длительность анимации в миллисекундах
11
11
  const stepTime = 100; // Интервал обновления в миллисекундах
12
- export const ProgressLoader = ({ value = 0, size = 'xl', showValue = true, animated = false, }) => {
12
+ export const ProgressLoader = ({ value = 0, size = 'xl', showValue = true, animated = false, testId = 'default' }) => {
13
13
  const [percent, setPercent] = useState(value);
14
14
  const spinnerSize = typeof size === 'string' ? spinnerSizes[size] : size;
15
15
  const validPercentage = Math.min(Math.max(value, 0), 100);
@@ -54,8 +54,8 @@ export const ProgressLoader = ({ value = 0, size = 'xl', showValue = true, anima
54
54
  setPercent(validPercentage);
55
55
  }
56
56
  }, [animated, validPercentage]);
57
- return (React.createElement("div", { className: progressLoaderWrapperClasses, style: { width: spinnerSize, height: spinnerSize } },
58
- React.createElement("svg", { id: "svg1", viewBox: `0 0 ${viewBoxSize} ${viewBoxSize}`, className: styles["progress-loader"] },
57
+ return (React.createElement("div", { className: progressLoaderWrapperClasses, style: { width: spinnerSize, height: spinnerSize }, "data-test-id": `${testId}-progressloader` },
58
+ React.createElement("svg", { id: "svg1", viewBox: `0 0 ${viewBoxSize} ${viewBoxSize}`, className: styles["progress-loader"], "data-test-id": `${testId}-progressloader-image` },
59
59
  React.createElement("circle", { cx: center, cy: center, r: radius, stroke: "#e5e5ea", strokeWidth: strokeWidth, fill: "none", style: { strokeLinecap: 'round' } }),
60
60
  React.createElement("circle", { cx: center, cy: center, r: radius, stroke: 'var(--blue-main)', strokeWidth: strokeWidth, fill: "none", style: {
61
61
  strokeDasharray: `${dashArray}`,
@@ -66,7 +66,7 @@ export const ProgressLoader = ({ value = 0, size = 'xl', showValue = true, anima
66
66
  //transition: animated ? 'stroke-dashoffset 0.5s ease-in-out' : 'none',
67
67
  } }, animated && (React.createElement("animate", { attributeName: "stroke-dashoffset", dur: `${animationDuration / 1000}`, values: `${circumference}; ${percent / 100}`, fill: "freeze" })))),
68
68
  showValue && size !== 'sm' && (React.createElement("div", { className: styles["progress-percentage"] },
69
- React.createElement(Typography, { variant: "Subheading2", color: '#9CA0A7', style: { fontSize: getTypographySize(), fontWeight: '300' } },
69
+ React.createElement(Typography, { variant: "Subheading2", color: '#9CA0A7', style: { fontSize: getTypographySize(), fontWeight: '300' }, testId: `${testId}-progressloader` },
70
70
  percent,
71
71
  "%")))));
72
72
  };
@@ -3,13 +3,13 @@ import styles from './RadioButton.module.css';
3
3
  import classNames from 'classnames';
4
4
  ;
5
5
  import { Typography } from '../Typography/Typography';
6
- export const RadioButton = ({ value, label, checked, onChange, disabled = false, size = 'sm' }) => {
6
+ export const RadioButton = ({ value, label, checked, onChange, disabled = false, size = 'sm', testId = 'default' }) => {
7
7
  const handleChange = (e) => {
8
8
  if (onChange) {
9
9
  onChange(e);
10
10
  }
11
11
  };
12
- return (React.createElement("label", { className: styles.radio },
13
- React.createElement("input", { type: "radio", checked: checked, value: value, onChange: handleChange, disabled: disabled, className: classNames(styles.input, styles[size]) }),
14
- React.createElement(Typography, { variant: 'Body2' }, label)));
12
+ return (React.createElement("label", { className: styles.radio, "data-test-id": `${testId}-radio` },
13
+ React.createElement("input", { type: "radio", name: "radio", checked: checked, value: value, onChange: handleChange, disabled: disabled, className: classNames(styles.input, styles[size]), "data-test-id": `${testId}-radio-input` }),
14
+ React.createElement(Typography, { variant: 'Body2', testId: `${testId}-radio` }, label)));
15
15
  };
@@ -2,15 +2,15 @@ import React, { useState } from 'react';
2
2
  import { Tag } from '../Tag/Tag';
3
3
  import ColorPicker from '../ColorPicker/ColorPicker';
4
4
  import styles from './SettingTag.module.css';
5
- export const SettingTag = ({ label, color, onChange }) => {
5
+ export const SettingTag = ({ label, color, onChange, testId = 'default' }) => {
6
6
  const [isHovered, setIsHovered] = useState(false);
7
7
  const [currentColor, setCurrentColor] = useState(color);
8
8
  const colorsOptions = ['red', 'orange', 'yellow', 'green', 'teal', 'blue', 'indigo', 'purple', 'pink'];
9
- return (React.createElement("div", { style: { display: 'flex', gap: `${isHovered ? '5px' : '10px'}`, flexDirection: 'row', alignItems: 'center' } },
10
- React.createElement(Tag, { label: label, color: currentColor, editable: true, onChange: onChange }),
9
+ return (React.createElement("div", { style: { display: 'flex', gap: `${isHovered ? '5px' : '10px'}`, flexDirection: 'row', alignItems: 'center' }, "data-test-id": `${testId}-settingtag` },
10
+ React.createElement(Tag, { label: label, color: currentColor, editable: true, onChange: onChange, testId: `${testId}-settingtag` }),
11
11
  !isHovered ? (React.createElement("div", { className: styles.circle, onMouseEnter: () => setIsHovered(true), style: {
12
12
  width: 10,
13
13
  height: 10,
14
14
  backgroundColor: (currentColor === null || currentColor === void 0 ? void 0 : currentColor.startsWith('#')) ? currentColor : `var(--${currentColor})`,
15
- } })) : (React.createElement(ColorPicker, { mainColor: currentColor, recentColors: isHovered ? colorsOptions : [], setIsHovered: setIsHovered, onChange: onChange, onColorChange: setCurrentColor }))));
15
+ }, "data-test-id": `${testId}-settingtag-color` })) : (React.createElement(ColorPicker, { mainColor: currentColor, recentColors: isHovered ? colorsOptions : [], setIsHovered: setIsHovered, onChange: onChange, onColorChange: setCurrentColor, testId: `${testId}-settingtag` }))));
16
16
  };
@@ -26,7 +26,7 @@ export const title = (lng) => ({
26
26
  warning: lng === 'ru' ? 'Внимание' : 'Warning',
27
27
  info: lng === 'ru' ? 'Информация' : 'Info',
28
28
  });
29
- export const Snackbar = ({ children, type, duration = 10000, icon = true, onClose, style, lng = 'ru' }) => {
29
+ export const Snackbar = ({ children, type, duration = 10000, icon = true, onClose, style, lng = 'ru', testId = 'default' }) => {
30
30
  const [isVisible, setIsVisible] = useState(true);
31
31
  const [isExiting, setIsExiting] = useState(false);
32
32
  useEffect(() => {
@@ -49,12 +49,12 @@ export const Snackbar = ({ children, type, duration = 10000, icon = true, onClos
49
49
  const snackbarClasses = classNames(styles['snackbar-wrapper'], styles[`snackbar--${type}`], {
50
50
  [styles['snackbar-wrapper--exiting']]: isExiting
51
51
  });
52
- return (React.createElement("div", { className: snackbarClasses, style: style },
53
- React.createElement("div", { className: styles['snackbar-textAndIcon'] },
52
+ return (React.createElement("div", { className: snackbarClasses, style: style, "data-test-id": `${testId}-snackbar-${type}` },
53
+ React.createElement("div", { className: styles['snackbar-textAndIcon'], "data-test-id": `${testId}-snackbar-${type}-icon` },
54
54
  icon && icons[type],
55
- React.createElement("div", { className: styles['snackbar-text'] },
56
- React.createElement(Typography, { variant: "Body1-Medium", color: 'var(--text-dark)' }, title(lng)[type]),
57
- React.createElement(Typography, { variant: "Body1", color: 'var(--text-btn-light)' }, children))),
58
- React.createElement("button", { className: styles.button, onClick: handleClose },
55
+ React.createElement("div", { className: styles['snackbar-text'], "data-test-id": `${testId}-snackbar-text` },
56
+ React.createElement(Typography, { variant: "Body1-Medium", color: 'var(--text-dark)', testId: `${testId}-snackbar-${type}-title` }, title(lng)[type]),
57
+ React.createElement(Typography, { variant: "Body1", color: 'var(--text-btn-light)', testId: `${testId}-snackbar-${type}-content` }, children))),
58
+ React.createElement("button", { className: styles.button, onClick: handleClose, "data-test-id": `${testId}-snackbar-${type}-close-button` },
59
59
  React.createElement(IconClose, { htmlColor: 'var(--text-btn-light)' }))));
60
60
  };
@@ -5,7 +5,7 @@ import styles from './Spinner.module.css';
5
5
  * Компонент Spinner отображает индикатор загрузки.
6
6
  */
7
7
  const spinnerSizes = { lg: 54, md: 34, sm: 24, xs: 8 };
8
- export const Spinner = ({ size = 'md', }) => {
8
+ export const Spinner = ({ size = 'md', testId = 'default' }) => {
9
9
  const spinnerSize = typeof size === 'string' ? spinnerSizes[size] : size;
10
10
  const viewBoxSize = 100;
11
11
  const strokeWidth = size === 'lg' || size === 'md' ? 12 : 10;
@@ -14,8 +14,8 @@ export const Spinner = ({ size = 'md', }) => {
14
14
  width: adjustedSize,
15
15
  height: adjustedSize,
16
16
  padding: strokeWidth
17
- } },
18
- React.createElement("svg", { id: "spinner", viewBox: `0 0 ${viewBoxSize} ${viewBoxSize}`, className: styles["spinner"], fill: "none", color: 'var(--blue-main)' },
17
+ }, "data-test-id": `${testId}-spinner` },
18
+ React.createElement("svg", { id: "spinner", viewBox: `0 0 ${viewBoxSize} ${viewBoxSize}`, className: styles["spinner"], fill: "none", color: 'var(--blue-main)', "data-test-id": `${testId}-spinner-svg` },
19
19
  React.createElement("defs", null,
20
20
  React.createElement("linearGradient", { id: "spinner-secondHalf" },
21
21
  React.createElement("stop", { offset: "0%", stopOpacity: "0", stopColor: "currentColor" }),