kamotive_ui 1.2.13 → 1.2.15
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/Icons/ChevronDown/ChevronDown10.d.ts +1 -0
- package/dist/Icons/ChevronDown/ChevronDown10.js +3 -2
- package/dist/Icons/IconAdd/IconAdd.d.ts +6 -0
- package/dist/Icons/IconAdd/IconAdd.js +5 -0
- package/dist/Icons/IconDownload/IconDownload.d.ts +7 -0
- package/dist/Icons/IconDownload/IconDownload.js +5 -0
- package/dist/Icons/index.d.ts +2 -0
- package/dist/Icons/index.js +2 -0
- package/dist/components/Checkbox/Checkbox.js +14 -2
- package/dist/components/Checkbox/Checkbox.module.css +25 -12
- package/dist/components/Checkbox/Checkbox.stories.d.ts +66 -0
- package/dist/components/Checkbox/Checkbox.stories.js +75 -0
- package/dist/components/FileAttach/FileAttach.js +4 -4
- package/dist/components/FileItem/FileItem.d.ts +3 -0
- package/dist/components/FileItem/FileItem.js +20 -0
- package/dist/components/FileItem/FileItem.module.css +45 -0
- package/dist/components/IconButton/IconButton.js +5 -3
- package/dist/components/List/List.d.ts +3 -0
- package/dist/components/List/List.js +91 -0
- package/dist/components/List/List.module.css +40 -0
- package/dist/components/ListItem/ListItem.d.ts +3 -0
- package/dist/components/ListItem/ListItem.js +41 -0
- package/dist/components/ListItem/ListItem.module.css +6 -0
- package/dist/components/Tag/Tag.d.ts +1 -0
- package/dist/components/Tag/Tag.js +1 -1
- package/dist/components/Tooltip/Tooltip.d.ts +3 -0
- package/dist/components/Tooltip/Tooltip.js +198 -0
- package/dist/components/Tooltip/Tooltip.module.css +22 -0
- package/dist/components/Typography/Typography.module.css +9 -9
- package/dist/index.d.ts +7 -2
- package/dist/index.js +6 -1
- package/dist/types/index.d.ts +95 -5
- package/package.json +1 -1
- package/dist/components/Loader/Loader.d.ts +0 -3
- package/dist/components/Loader/Loader.js +0 -18
- package/dist/components/Loader/Loader.module.css +0 -75
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
export const ChevronDown10 = ({ color = 'inherit', htmlColor, strokeWidth, }) => {
|
|
2
|
+
export const ChevronDown10 = ({ color = 'inherit', htmlColor, strokeWidth, rotation = 0, }) => {
|
|
3
3
|
return (React.createElement("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", className: color },
|
|
4
|
-
React.createElement("
|
|
4
|
+
React.createElement("g", { transform: `rotate(${rotation}, 12, 12)` },
|
|
5
|
+
React.createElement("path", { fill: htmlColor || 'currentColor', stroke: htmlColor || 'currentColor', strokeWidth: strokeWidth || '0', d: "M5.84,9.59L11.5,15.25L17.16,9.59L16.45,8.89L11.5,13.84L6.55,8.89L5.84,9.59Z" }))));
|
|
5
6
|
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export const IconAdd = ({ color = 'inherit', htmlColor, strokeWidth, }) => {
|
|
3
|
+
return (React.createElement("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", className: color },
|
|
4
|
+
React.createElement("path", { fill: htmlColor || 'currentColor', stroke: htmlColor || 'currentColor', strokeWidth: strokeWidth || '0', d: "M5,13V12H11V6H12V12H18V13H12V19H11V13H5Z" })));
|
|
5
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export const IconDownload = ({ color = 'inherit', htmlColor, strokeWidth, onClick, }) => {
|
|
3
|
+
return (React.createElement("svg", { width: "15", height: "15", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", className: color, onClick: onClick },
|
|
4
|
+
React.createElement("path", { fill: htmlColor || 'currentColor', stroke: htmlColor || 'currentColor', strokeWidth: strokeWidth || '0', d: "M12,4V16.25L17.25,11L18,11.66L11.5,18.16L5,11.66L5.75,11L11,16.25V4H12M3,19H4V21H19V19H20V22H3V19Z" })));
|
|
5
|
+
};
|
package/dist/Icons/index.d.ts
CHANGED
|
@@ -18,3 +18,5 @@ export { IconClose10 } from './IconClose/IconClose10';
|
|
|
18
18
|
export { IconColorPicker10 } from './IconColorPicker/IconColorPicker10';
|
|
19
19
|
export { IconFile } from './IconFile/IconFile';
|
|
20
20
|
export { IconUpload } from './IconUpload/IconUpload';
|
|
21
|
+
export { IconDownload } from './IconDownload/IconDownload';
|
|
22
|
+
export { IconAdd } from './IconAdd/IconAdd';
|
package/dist/Icons/index.js
CHANGED
|
@@ -18,3 +18,5 @@ export { IconClose10 } from './IconClose/IconClose10';
|
|
|
18
18
|
export { IconColorPicker10 } from './IconColorPicker/IconColorPicker10';
|
|
19
19
|
export { IconFile } from './IconFile/IconFile';
|
|
20
20
|
export { IconUpload } from './IconUpload/IconUpload';
|
|
21
|
+
export { IconDownload } from './IconDownload/IconDownload';
|
|
22
|
+
export { IconAdd } from './IconAdd/IconAdd';
|
|
@@ -3,13 +3,25 @@ import styles from './Checkbox.module.css';
|
|
|
3
3
|
import classNames from 'classnames';
|
|
4
4
|
;
|
|
5
5
|
import { Typography } from '../Typography/Typography';
|
|
6
|
-
export const Checkbox = ({ checked, onChange, disabled = false, size = 'sm', label }) => {
|
|
6
|
+
export const Checkbox = ({ checked, onChange, disabled = false, size = 'sm', label, color, filled }) => {
|
|
7
7
|
const handleChange = (e) => {
|
|
8
8
|
if (onChange) {
|
|
9
9
|
onChange(e);
|
|
10
10
|
}
|
|
11
11
|
};
|
|
12
|
-
|
|
12
|
+
const checkboxStyles = {
|
|
13
|
+
'--border-color': color || 'var(--icons-active)',
|
|
14
|
+
'--border-color-hover': color ? 'color-mix(in srgb, var(--border-color) 60%, white)' : 'var(--blue-main)',
|
|
15
|
+
'--border-color-checked': color || 'var(--icons-medium)',
|
|
16
|
+
'--border-color-disabled': color ? 'color-mix(in srgb, var(--border-color) 30%, white)' : 'var(--icons-light)',
|
|
17
|
+
'--background-color-hover': filled ? 'var(--border-color-hover)' : 'var(--white)',
|
|
18
|
+
'--background-color-checked': filled ? 'var(--border-color-checked)' : 'var(--white)',
|
|
19
|
+
'--background-color-disabled': filled ? 'var(--border-color-disabled)' : 'var(--white)',
|
|
20
|
+
'--arrow-color': filled ? 'var(--white)' : 'var(--border-color-checked)',
|
|
21
|
+
'--arrow-color-hover': filled ? 'var(--white)' : 'var(--border-color-hover)',
|
|
22
|
+
'--arrow-color-disabled': filled ? 'var(--white)' : 'var(--border-color-disabled)',
|
|
23
|
+
};
|
|
24
|
+
return (React.createElement("label", { className: styles.checkbox, style: checkboxStyles },
|
|
13
25
|
React.createElement("input", { type: "checkbox", checked: checked, onChange: handleChange, disabled: disabled, className: classNames(styles.input, styles[size]) }),
|
|
14
26
|
React.createElement(Typography, { variant: 'Body2' }, label)));
|
|
15
27
|
};
|
|
@@ -23,23 +23,26 @@
|
|
|
23
23
|
display: inline-block;
|
|
24
24
|
padding: 6px;
|
|
25
25
|
|
|
26
|
-
border: 1px solid var(--
|
|
26
|
+
border: 1px solid var(--border-color);
|
|
27
27
|
border-radius: 3px;
|
|
28
28
|
background-color: var(--white);
|
|
29
|
-
background-clip: content-box;
|
|
30
29
|
position: relative;
|
|
31
30
|
cursor: pointer;
|
|
32
31
|
|
|
33
32
|
}
|
|
34
33
|
|
|
35
|
-
.input[type="checkbox"]:hover
|
|
36
|
-
|
|
37
|
-
.input[type="checkbox"]:checked:hover::after {
|
|
38
|
-
border-color: var(--blue-main);
|
|
34
|
+
.input[type="checkbox"]:hover {
|
|
35
|
+
border-color: var(--border-color-hover);
|
|
39
36
|
}
|
|
40
37
|
|
|
41
38
|
.input[type="checkbox"]:checked {
|
|
42
|
-
border-color: var(--
|
|
39
|
+
border-color: var(--border-color-checked);
|
|
40
|
+
background-color: var(--background-color-checked);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.input[type="checkbox"]:checked:hover {
|
|
44
|
+
border-color: var(--border-color-hover);
|
|
45
|
+
background-color: var(--background-color-hover);
|
|
43
46
|
}
|
|
44
47
|
|
|
45
48
|
.input[type="checkbox"]:checked::after {
|
|
@@ -52,16 +55,26 @@
|
|
|
52
55
|
width: 40%;
|
|
53
56
|
height: 75%;
|
|
54
57
|
|
|
55
|
-
border: solid var(--
|
|
58
|
+
border: solid var(--arrow-color);
|
|
56
59
|
border-width: 0 2px 2px 0;
|
|
57
60
|
background-color: none;
|
|
58
61
|
}
|
|
59
62
|
|
|
60
|
-
.input[type="checkbox"]:
|
|
61
|
-
|
|
62
|
-
|
|
63
|
+
.input[type="checkbox"]:checked:hover::after {
|
|
64
|
+
border-color: var(--arrow-color-hover);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.input[type="checkbox"]:disabled {
|
|
63
68
|
background-color: var(--white);
|
|
64
|
-
border-color: var(--
|
|
69
|
+
border-color: var(--border-color-disabled);
|
|
65
70
|
cursor: not-allowed;
|
|
66
71
|
box-shadow: none;
|
|
67
72
|
}
|
|
73
|
+
|
|
74
|
+
.input[type="checkbox"]:disabled:checked {
|
|
75
|
+
background-color: var(--background-color-disabled);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.input[type="checkbox"]:disabled:checked:after {
|
|
79
|
+
border-color: var(--arrow-color-disabled);
|
|
80
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { ChangeEventHandler } from 'react';
|
|
2
|
+
import type { Meta } from '@storybook/react';
|
|
3
|
+
export interface CheckboxProps {
|
|
4
|
+
/** Идентификатор */
|
|
5
|
+
checked?: boolean;
|
|
6
|
+
/** Обработчик изменения состояния */
|
|
7
|
+
onChange?: ChangeEventHandler<HTMLInputElement>;
|
|
8
|
+
/** Заблокированный чекбокс */
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
/** Размер чекбокса */
|
|
11
|
+
size?: 'sm' | 'md';
|
|
12
|
+
/** Текст лейбла */
|
|
13
|
+
label?: string;
|
|
14
|
+
}
|
|
15
|
+
declare const meta: Meta<CheckboxProps>;
|
|
16
|
+
export default meta;
|
|
17
|
+
export declare const CheckboxOff: {
|
|
18
|
+
(argTypes: CheckboxProps): JSX.Element;
|
|
19
|
+
storyName: string;
|
|
20
|
+
};
|
|
21
|
+
export declare const CheckboxLabel: {
|
|
22
|
+
(argTypes: CheckboxProps): JSX.Element;
|
|
23
|
+
storyName: string;
|
|
24
|
+
args: {
|
|
25
|
+
label: string;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
export declare const CheckboxChecked: {
|
|
29
|
+
(argTypes: CheckboxProps): JSX.Element;
|
|
30
|
+
storyName: string;
|
|
31
|
+
args: {
|
|
32
|
+
checked: boolean;
|
|
33
|
+
disabled: boolean;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
export declare const CheckboxDisabled: {
|
|
37
|
+
(argTypes: CheckboxProps): JSX.Element;
|
|
38
|
+
storyName: string;
|
|
39
|
+
args: {
|
|
40
|
+
checked: boolean;
|
|
41
|
+
disabled: boolean;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
export declare const CheckboxCheckedDisabled: {
|
|
45
|
+
(argTypes: CheckboxProps): JSX.Element;
|
|
46
|
+
storyName: string;
|
|
47
|
+
args: {
|
|
48
|
+
checked: boolean;
|
|
49
|
+
disabled: boolean;
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
export declare const CheckboxCustomColor: {
|
|
53
|
+
(argTypes: CheckboxProps): JSX.Element;
|
|
54
|
+
storyName: string;
|
|
55
|
+
args: {
|
|
56
|
+
color: string;
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
export declare const CheckboxCustomColorFilled: {
|
|
60
|
+
(argTypes: CheckboxProps): JSX.Element;
|
|
61
|
+
storyName: string;
|
|
62
|
+
args: {
|
|
63
|
+
color: string;
|
|
64
|
+
filled: boolean;
|
|
65
|
+
};
|
|
66
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { Checkbox } from './Checkbox';
|
|
3
|
+
const meta = {
|
|
4
|
+
component: Checkbox,
|
|
5
|
+
parameters: {
|
|
6
|
+
layout: 'centered',
|
|
7
|
+
},
|
|
8
|
+
tags: ['autodocs'],
|
|
9
|
+
decorators: [
|
|
10
|
+
(Story) => (React.createElement("div", { style: {
|
|
11
|
+
backgroundColor: 'var(--white)',
|
|
12
|
+
padding: '30px',
|
|
13
|
+
borderRadius: '10px',
|
|
14
|
+
width: '900px'
|
|
15
|
+
} },
|
|
16
|
+
React.createElement(Story, null))),
|
|
17
|
+
],
|
|
18
|
+
args: {
|
|
19
|
+
size: 'sm',
|
|
20
|
+
disabled: false,
|
|
21
|
+
},
|
|
22
|
+
argTypes: {
|
|
23
|
+
size: {
|
|
24
|
+
description: 'Свойство, позволяющее регулировать размер чекбокса',
|
|
25
|
+
control: { type: 'radio' },
|
|
26
|
+
options: ['sm', 'md'],
|
|
27
|
+
},
|
|
28
|
+
disabled: { description: 'Устанавливает атрибут disabled', control: { type: 'boolean' } },
|
|
29
|
+
checked: { description: 'Задаёт включённое состояние для компонента' },
|
|
30
|
+
label: { description: 'Текст лейбла чекбокса', type: 'string' },
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
export default meta;
|
|
34
|
+
export const CheckboxOff = (argTypes) => {
|
|
35
|
+
const [checked, setChecked] = useState(false);
|
|
36
|
+
const handleChange = () => {
|
|
37
|
+
setChecked(prev => !prev);
|
|
38
|
+
};
|
|
39
|
+
return (React.createElement(Checkbox, Object.assign({ checked: checked, onChange: handleChange }, argTypes)));
|
|
40
|
+
};
|
|
41
|
+
CheckboxOff.storyName = 'Checkbox по умолчанию';
|
|
42
|
+
export const CheckboxLabel = (argTypes) => React.createElement(Checkbox, Object.assign({}, argTypes));
|
|
43
|
+
CheckboxLabel.storyName = 'Checkbox c label';
|
|
44
|
+
CheckboxLabel.args = {
|
|
45
|
+
label: 'Чекбокс',
|
|
46
|
+
};
|
|
47
|
+
export const CheckboxChecked = (argTypes) => React.createElement(Checkbox, Object.assign({}, argTypes));
|
|
48
|
+
CheckboxChecked.storyName = 'Checkbox выбран';
|
|
49
|
+
CheckboxChecked.args = {
|
|
50
|
+
checked: true,
|
|
51
|
+
disabled: false,
|
|
52
|
+
};
|
|
53
|
+
export const CheckboxDisabled = (argTypes) => React.createElement(Checkbox, Object.assign({}, argTypes));
|
|
54
|
+
CheckboxDisabled.storyName = 'Checkbox заблокирован';
|
|
55
|
+
CheckboxDisabled.args = {
|
|
56
|
+
checked: false,
|
|
57
|
+
disabled: true,
|
|
58
|
+
};
|
|
59
|
+
export const CheckboxCheckedDisabled = (argTypes) => React.createElement(Checkbox, Object.assign({}, argTypes));
|
|
60
|
+
CheckboxCheckedDisabled.storyName = 'Checkbox выбран и заблокирован';
|
|
61
|
+
CheckboxCheckedDisabled.args = {
|
|
62
|
+
checked: true,
|
|
63
|
+
disabled: true,
|
|
64
|
+
};
|
|
65
|
+
export const CheckboxCustomColor = (argTypes) => React.createElement(Checkbox, Object.assign({}, argTypes));
|
|
66
|
+
CheckboxCustomColor.storyName = 'Checkbox с кастомным цветом';
|
|
67
|
+
CheckboxCustomColor.args = {
|
|
68
|
+
color: 'red',
|
|
69
|
+
};
|
|
70
|
+
export const CheckboxCustomColorFilled = (argTypes) => React.createElement(Checkbox, Object.assign({}, argTypes));
|
|
71
|
+
CheckboxCustomColorFilled.storyName = 'Checkbox с кастомным цветом заполненный';
|
|
72
|
+
CheckboxCustomColorFilled.args = {
|
|
73
|
+
color: 'red',
|
|
74
|
+
filled: true,
|
|
75
|
+
};
|
|
@@ -3,13 +3,13 @@ import { useDropzone } from 'react-dropzone';
|
|
|
3
3
|
import styles from './FileAttach.module.css';
|
|
4
4
|
import { Typography } from '../Typography/Typography';
|
|
5
5
|
import { IconUpload } from '../../Icons';
|
|
6
|
-
import {
|
|
6
|
+
import { FileItem } from '../FileItem/FileItem';
|
|
7
7
|
import classNames from 'classnames';
|
|
8
8
|
export const FileAttach = ({ maxFileSize = 2, maxFileCount = 10, acceptedFormats = {
|
|
9
9
|
'image/*': ['.png', '.gif', '.jpeg', '.jpg'],
|
|
10
10
|
'application/pdf': ['.pdf'],
|
|
11
11
|
'application/msword': ['.doc', '.docx'],
|
|
12
|
-
}, addedFiles, setAddedFiles, disabled = false, className, style, }) => {
|
|
12
|
+
}, addedFiles, setAddedFiles, onDownload, disabled = false, className, style, }) => {
|
|
13
13
|
const [errorFiles, setErrorFiles] = useState([]);
|
|
14
14
|
const fileValidator = (file) => {
|
|
15
15
|
if (file.size > maxFileSize * 1024 * 1024 * 1024) {
|
|
@@ -42,8 +42,8 @@ export const FileAttach = ({ maxFileSize = 2, maxFileCount = 10, acceptedFormats
|
|
|
42
42
|
maxFiles: maxFileCount,
|
|
43
43
|
disabled: disabled,
|
|
44
44
|
});
|
|
45
|
-
const acceptedFileItems = addedFiles.map((file, index) => (React.createElement(
|
|
46
|
-
const fileRejectionItems = errorFiles.map(({ file, errors }) => (React.createElement(
|
|
45
|
+
const acceptedFileItems = addedFiles.map((file, index) => (React.createElement(FileItem, { name: file.name, size: file.size, onDelete: () => deleteAcceptedFile(addedFiles, setAddedFiles, file.name), onDownload: onDownload, key: index })));
|
|
46
|
+
const fileRejectionItems = errorFiles.map(({ file, errors }) => (React.createElement(FileItem, { name: file.name, size: file.size, error: errors[0].message, onDelete: () => deleteRejectedFile(errorFiles, setErrorFiles, file.name), key: file.path })));
|
|
47
47
|
const deleteAcceptedFile = (addedFiles, setAddedFiles, fileName) => {
|
|
48
48
|
setAddedFiles(addedFiles.filter((file) => file.name !== fileName));
|
|
49
49
|
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import styles from './FileItem.module.css';
|
|
3
|
+
import { Typography } from '../Typography/Typography';
|
|
4
|
+
import { ProgressBar } from '../ProgressBar/ProgressBar';
|
|
5
|
+
import { IconButton } from '../IconButton/IconButton';
|
|
6
|
+
import { IconClose10, IconDownload, IconFile } from '../../Icons';
|
|
7
|
+
export const FileItem = ({ name, size = 0, loading = false, error = '', onDownload, onDelete, style }) => {
|
|
8
|
+
return (React.createElement("div", { className: `${styles['fileItem']} ${error ? styles['error'] : ''}`, style: style },
|
|
9
|
+
React.createElement("div", { className: styles['fileItemFile'] },
|
|
10
|
+
React.createElement("div", { className: styles['fileItemInfo'] },
|
|
11
|
+
React.createElement("div", { className: styles['fileItemIcon'] },
|
|
12
|
+
React.createElement(IconFile, { htmlColor: 'var(--icons-grey)' })),
|
|
13
|
+
React.createElement("div", { className: styles['fileItemName'] },
|
|
14
|
+
React.createElement(Typography, { variant: "Body1", color: "var(--text-dark)" }, name),
|
|
15
|
+
size !== 0 && (React.createElement(Typography, { variant: "Caption", color: "var(--grey-medium)" }, `${(size / 1024).toFixed(1)} кБ`)))),
|
|
16
|
+
onDownload && (React.createElement(IconButton, { icon: React.createElement(IconDownload, null), onClick: onDownload, color: 'var(--icons-grey)', className: styles['fileIcon'] })),
|
|
17
|
+
onDelete && (React.createElement(IconButton, { icon: React.createElement(IconClose10, null), onClick: onDelete, color: 'var(--icons-grey)' }))),
|
|
18
|
+
loading && React.createElement(ProgressBar, { animated: true, size: "sm", value: 100 }),
|
|
19
|
+
error && (React.createElement(Typography, { variant: "Caption", color: "var(--error-main)" }, error))));
|
|
20
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
|
|
2
|
+
.fileItem {
|
|
3
|
+
display: flex;
|
|
4
|
+
flex-direction: column;
|
|
5
|
+
gap: 5px;
|
|
6
|
+
justify-content: space-between;
|
|
7
|
+
|
|
8
|
+
padding: 10px 15px;
|
|
9
|
+
border: 1px solid var(--info-secondary);
|
|
10
|
+
border-radius: 10px;
|
|
11
|
+
|
|
12
|
+
}
|
|
13
|
+
.error {
|
|
14
|
+
border-color: var(--error-main);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.fileItemFile{
|
|
18
|
+
display: flex;
|
|
19
|
+
flex-direction: row;
|
|
20
|
+
align-items: center;
|
|
21
|
+
}
|
|
22
|
+
.fileItemInfo {
|
|
23
|
+
display: flex;
|
|
24
|
+
flex-direction: row;
|
|
25
|
+
gap: 5px;
|
|
26
|
+
flex-grow: 1;
|
|
27
|
+
align-items: flex-start;
|
|
28
|
+
overflow: hidden;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.fileItemIcon {
|
|
32
|
+
flex-shrink: 0
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.fileItemName {
|
|
36
|
+
display: flex;
|
|
37
|
+
flex-direction: column;
|
|
38
|
+
flex-grow: 1;
|
|
39
|
+
align-items: flex-start;
|
|
40
|
+
overflow: auto;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.fileIcon svg path {
|
|
44
|
+
stroke-width: 0.8;
|
|
45
|
+
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import classNames from 'classnames';
|
|
3
3
|
import styles from './IconButton.module.css';
|
|
4
|
-
export const IconButton = ({ icon, size = 'md', color, style, disabled = false, onClick, children, }) => {
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
export const IconButton = ({ icon, size = 'md', color, style, disabled = false, onClick, children, className }) => {
|
|
5
|
+
const validChildren = React.Children.toArray(children).filter(child => React.isValidElement(child));
|
|
6
|
+
const renderIcon = icon || validChildren[0];
|
|
7
|
+
return (React.createElement("button", { className: classNames(styles['iconButton'], styles[`iconButton--${size}`], className), disabled: disabled, "aria-disabled": disabled, type: "button", onClick: onClick, style: style }, (renderIcon) &&
|
|
8
|
+
React.cloneElement(renderIcon, {
|
|
7
9
|
htmlColor: color,
|
|
8
10
|
strokeWidth: size === 'lg' ? '0.5' : size === 'md' ? '0.3' : '0.0',
|
|
9
11
|
})));
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
|
+
import classNames from 'classnames';
|
|
3
|
+
import styles from './List.module.css';
|
|
4
|
+
import { Typography } from '../Typography/Typography';
|
|
5
|
+
import { Checkbox } from '../Checkbox/Checkbox';
|
|
6
|
+
import { RadioButton } from '../RadioButton/RadioButton';
|
|
7
|
+
import { ChevronDown10 } from '../../Icons';
|
|
8
|
+
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, children, isHeader = false, parentChecked = false, }) => {
|
|
9
|
+
const [isOpen, setIsOpen] = useState(open);
|
|
10
|
+
const [isChecked, setIsChecked] = useState(checked || parentChecked);
|
|
11
|
+
const childIds = [];
|
|
12
|
+
React.Children.forEach(children, (child) => {
|
|
13
|
+
if (React.isValidElement(child) && child.props.id) {
|
|
14
|
+
childIds.push(child.props.id);
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
const handleClick = (e) => {
|
|
18
|
+
if (collapsible) {
|
|
19
|
+
setIsOpen(!isOpen);
|
|
20
|
+
}
|
|
21
|
+
if (onClick) {
|
|
22
|
+
onClick();
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
const handleChildCheck = (childId, isChecked) => {
|
|
26
|
+
if (onCheck) {
|
|
27
|
+
onCheck(childId, isChecked);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
const handleChildRadioSelect = (childId) => {
|
|
31
|
+
if (onRadioSelect) {
|
|
32
|
+
onRadioSelect(childId);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
const handleCheckboxClick = (e) => {
|
|
36
|
+
e.stopPropagation();
|
|
37
|
+
const newCheckedState = !isChecked;
|
|
38
|
+
setIsChecked(newCheckedState);
|
|
39
|
+
if (onCheck) {
|
|
40
|
+
onCheck(id || "", newCheckedState);
|
|
41
|
+
}
|
|
42
|
+
if (childIds.length > 0 && onCheck) {
|
|
43
|
+
childIds.forEach((childId) => {
|
|
44
|
+
onCheck(childId, newCheckedState);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
const handleRadioClick = (e) => {
|
|
49
|
+
e.stopPropagation();
|
|
50
|
+
if (id && onRadioSelect) {
|
|
51
|
+
onRadioSelect(id);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
setIsChecked(parentChecked || checked);
|
|
56
|
+
}, [parentChecked, checked]);
|
|
57
|
+
const headerClassNames = classNames(styles.header, className);
|
|
58
|
+
const contentClassNames = classNames(styles.content, isOpen ? styles['content--expanded'] : styles['content--collapsed']);
|
|
59
|
+
return (React.createElement("div", { className: styles.collapsibleList },
|
|
60
|
+
label && (React.createElement("div", { className: headerClassNames, onClick: handleClick, style: style },
|
|
61
|
+
!isHeader && (React.createElement("div", null,
|
|
62
|
+
withCheckbox && (React.createElement("span", { onClick: handleCheckboxClick },
|
|
63
|
+
React.createElement(Checkbox, { checked: isChecked, color: checkboxColor, filled: checkboxFilled, disabled: disabled }))),
|
|
64
|
+
withRadioButton && (React.createElement("span", { onClick: handleRadioClick },
|
|
65
|
+
React.createElement(RadioButton, { checked: selected, value: id, disabled: disabled }))),
|
|
66
|
+
customBullet && React.createElement("span", { className: classNames(styles.bullet, bulletClassName) }, customBullet))),
|
|
67
|
+
React.createElement(Typography, { variant: "Body1" }, label),
|
|
68
|
+
collapsible && (React.createElement("span", { className: styles.indicator }, isOpen ? React.createElement(ChevronDown10, null) : React.createElement(ChevronDown10, { rotation: 270 }))))),
|
|
69
|
+
React.createElement("div", { className: collapsible ? contentClassNames : styles.content, style: { paddingLeft: !label ? 0 : '16px' } }, React.Children.map(children, (child) => {
|
|
70
|
+
if (React.isValidElement(child)) {
|
|
71
|
+
return React.cloneElement(child, {
|
|
72
|
+
bulletClassName: classNames(styles.bullet, child.props.bulletClassName || bulletClassName),
|
|
73
|
+
customBullet: child.props.customBullet !== undefined
|
|
74
|
+
? child.props.customBullet
|
|
75
|
+
: customItemBullet !== undefined
|
|
76
|
+
? customItemBullet
|
|
77
|
+
: customBullet,
|
|
78
|
+
withCheckbox: child.props.withCheckbox !== undefined ? child.props.withCheckbox : withCheckbox,
|
|
79
|
+
checkboxFilled: child.props.checkboxFilled !== undefined ? child.props.checkboxFilled : checkboxFilled,
|
|
80
|
+
withRadioButton: child.props.withRadioButton !== undefined ? child.props.withRadioButton : withRadioButton,
|
|
81
|
+
onCheck: handleChildCheck,
|
|
82
|
+
onRadioSelect: handleChildRadioSelect,
|
|
83
|
+
parentChecked: isChecked,
|
|
84
|
+
selected: child.props.selected,
|
|
85
|
+
style: child.props.style || style,
|
|
86
|
+
className: child.props.className,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
return child;
|
|
90
|
+
}))));
|
|
91
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
.collapsibleList {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
width: 100%;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.header {
|
|
8
|
+
display: flex;
|
|
9
|
+
align-items: center;
|
|
10
|
+
cursor: pointer;
|
|
11
|
+
padding: 8px;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.checkbox--active {
|
|
15
|
+
font-weight: bold;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.content {
|
|
19
|
+
transition: max-height 0.3s ease-out;
|
|
20
|
+
overflow: hidden;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.content--expanded {
|
|
24
|
+
max-height: fit-content;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.content--collapsed {
|
|
28
|
+
max-height: 0;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.bullet {
|
|
32
|
+
margin-right: 10px;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.indicator {
|
|
36
|
+
margin-left: auto;
|
|
37
|
+
font-size: 12px;
|
|
38
|
+
display: flex;
|
|
39
|
+
justify-content: center;
|
|
40
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import React, { useEffect, useState } from 'react';
|
|
2
|
+
import classNames from 'classnames';
|
|
3
|
+
import styles from './ListItem.module.css';
|
|
4
|
+
import { Typography } from '../Typography/Typography';
|
|
5
|
+
import { Checkbox } from '../Checkbox/Checkbox';
|
|
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, }) => {
|
|
8
|
+
const [isChecked, setIsChecked] = useState(checked || parentChecked);
|
|
9
|
+
const itemClassNames = classNames(className, styles.listItem);
|
|
10
|
+
const handleClick = (e) => {
|
|
11
|
+
if (onClick) {
|
|
12
|
+
e.stopPropagation();
|
|
13
|
+
onClick();
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
const handleCheckboxClick = (e) => {
|
|
17
|
+
e.stopPropagation();
|
|
18
|
+
const newCheckedState = !isChecked;
|
|
19
|
+
setIsChecked(newCheckedState);
|
|
20
|
+
if (onCheck) {
|
|
21
|
+
onCheck(id || "", newCheckedState);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
const handleRadioClick = (e) => {
|
|
25
|
+
e.stopPropagation();
|
|
26
|
+
if (id && onRadioSelect) {
|
|
27
|
+
onRadioSelect(id);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
setIsChecked(parentChecked || checked);
|
|
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),
|
|
40
|
+
children));
|
|
41
|
+
};
|
|
@@ -2,7 +2,7 @@ import React, { useEffect, useRef, useState } from 'react';
|
|
|
2
2
|
;
|
|
3
3
|
import styles from './Tag.module.css';
|
|
4
4
|
import classNames from 'classnames';
|
|
5
|
-
const hexToRgba = (hex, alpha) => {
|
|
5
|
+
export const hexToRgba = (hex, alpha) => {
|
|
6
6
|
//преобразуем в rgba для заднего фона
|
|
7
7
|
const r = parseInt(hex.slice(1, 3), 16);
|
|
8
8
|
const g = parseInt(hex.slice(3, 5), 16);
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import React, { useEffect, useRef, useState } from 'react';
|
|
2
|
+
import styles from './Tooltip.module.css';
|
|
3
|
+
import { Typography } from '../Typography/Typography';
|
|
4
|
+
import classNames from 'classnames';
|
|
5
|
+
import ReactDOM from 'react-dom';
|
|
6
|
+
import { hexToRgba } from '../Tag/Tag';
|
|
7
|
+
export const Tooltip = ({ label, children, className, style, overlayChildren = false, textSize = 'sm', position = 'none', displayDelay = 750, hideDelay = 500, opacity = 0.4, color, followCursor = false, }) => {
|
|
8
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
9
|
+
const [isVisible, setIsVisible] = useState(false);
|
|
10
|
+
const [coords, setCoords] = useState({ x: 0, y: 0 });
|
|
11
|
+
const [childrenRect, setChildrenRect] = useState({
|
|
12
|
+
x: 0,
|
|
13
|
+
y: 0,
|
|
14
|
+
width: 0,
|
|
15
|
+
height: 0,
|
|
16
|
+
contentX: 0,
|
|
17
|
+
contentY: 0,
|
|
18
|
+
contentWidth: 0,
|
|
19
|
+
contentHeight: 0,
|
|
20
|
+
});
|
|
21
|
+
const timeoutRef = useRef(null);
|
|
22
|
+
const mousePositionRef = useRef({ x: 0, y: 0 });
|
|
23
|
+
const childrenRef = useRef(null);
|
|
24
|
+
const tooltipElementRef = useRef(null);
|
|
25
|
+
const updateContainerRect = () => {
|
|
26
|
+
if (childrenRef.current) {
|
|
27
|
+
const childElement = childrenRef.current.firstElementChild;
|
|
28
|
+
const rect = childElement.getBoundingClientRect();
|
|
29
|
+
const computedStyle = window.getComputedStyle(childElement);
|
|
30
|
+
const paddingTop = parseFloat(computedStyle.paddingTop);
|
|
31
|
+
const paddingBottom = parseFloat(computedStyle.paddingBottom);
|
|
32
|
+
const paddingLeft = parseFloat(computedStyle.paddingLeft);
|
|
33
|
+
const paddingRight = parseFloat(computedStyle.paddingRight);
|
|
34
|
+
const contentX = rect.left + paddingLeft;
|
|
35
|
+
const contentY = rect.top + paddingTop;
|
|
36
|
+
const contentHeight = rect.height - paddingTop - paddingBottom;
|
|
37
|
+
const contentWidth = rect.width - paddingLeft - paddingRight;
|
|
38
|
+
setChildrenRect({
|
|
39
|
+
x: rect.left,
|
|
40
|
+
y: rect.top,
|
|
41
|
+
width: rect.width,
|
|
42
|
+
height: rect.height,
|
|
43
|
+
contentX: contentX,
|
|
44
|
+
contentY: contentY,
|
|
45
|
+
contentWidth: contentWidth,
|
|
46
|
+
contentHeight: contentHeight,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
updateContainerRect();
|
|
52
|
+
window.addEventListener('resize', updateContainerRect);
|
|
53
|
+
window.addEventListener('scroll', updateContainerRect);
|
|
54
|
+
return () => {
|
|
55
|
+
window.removeEventListener('resize', updateContainerRect);
|
|
56
|
+
window.removeEventListener('scroll', updateContainerRect);
|
|
57
|
+
};
|
|
58
|
+
}, []);
|
|
59
|
+
const adjustToViewPort = (posX, posY) => {
|
|
60
|
+
if (tooltipElementRef.current) {
|
|
61
|
+
const OFFSET = 15;
|
|
62
|
+
const tooltipWidth = tooltipElementRef.current.offsetWidth;
|
|
63
|
+
const tooltipHeight = tooltipElementRef.current.offsetHeight;
|
|
64
|
+
const viewportWidth = window.innerWidth;
|
|
65
|
+
const viewportHeight = window.innerHeight;
|
|
66
|
+
if (posX + tooltipWidth > viewportWidth) {
|
|
67
|
+
posX = viewportWidth - tooltipWidth - OFFSET;
|
|
68
|
+
}
|
|
69
|
+
if (posY + tooltipHeight > viewportHeight) {
|
|
70
|
+
posY = mousePositionRef.current.y - tooltipHeight - OFFSET;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return [posX, posY];
|
|
74
|
+
};
|
|
75
|
+
const updateCoords = (mouseX, mouseY) => {
|
|
76
|
+
const OFFSET_X = 8;
|
|
77
|
+
const OFFSET_Y = 15;
|
|
78
|
+
const CONTENT_OFFSET_Y = 5;
|
|
79
|
+
const cursorX = mouseX !== undefined ? mouseX : mousePositionRef.current.x;
|
|
80
|
+
const cursorY = mouseY !== undefined ? mouseY : mousePositionRef.current.y;
|
|
81
|
+
// Если followCursor активен, всегда используем позицию курсора
|
|
82
|
+
if (followCursor) {
|
|
83
|
+
let posX = cursorX + OFFSET_X;
|
|
84
|
+
let posY = cursorY + OFFSET_Y;
|
|
85
|
+
// Проверяем границы экрана
|
|
86
|
+
[posX, posY] = adjustToViewPort(posX, posY);
|
|
87
|
+
setCoords({
|
|
88
|
+
x: posX,
|
|
89
|
+
y: posY
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
// Оригинальная логика позиционирования
|
|
94
|
+
let posX = cursorX + OFFSET_X;
|
|
95
|
+
let posY = overlayChildren || cursorY > childrenRect.contentY + childrenRect.contentHeight
|
|
96
|
+
? cursorY + OFFSET_Y
|
|
97
|
+
: childrenRect.contentY + childrenRect.contentHeight + CONTENT_OFFSET_Y;
|
|
98
|
+
if (position === 'bottom-center' || position === 'bottom-right' || position === 'bottom-left') {
|
|
99
|
+
posY = childrenRect.contentY + childrenRect.contentHeight + CONTENT_OFFSET_Y;
|
|
100
|
+
}
|
|
101
|
+
else if (position !== 'none') {
|
|
102
|
+
posY = childrenRect.contentY - childrenRect.contentHeight - CONTENT_OFFSET_Y;
|
|
103
|
+
}
|
|
104
|
+
setCoords({
|
|
105
|
+
x: posX,
|
|
106
|
+
y: posY
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
if (!isOpen) {
|
|
110
|
+
setIsOpen(true);
|
|
111
|
+
setTimeout(() => {
|
|
112
|
+
setIsVisible(true);
|
|
113
|
+
}, 10);
|
|
114
|
+
}
|
|
115
|
+
if (!followCursor) {
|
|
116
|
+
/** положение подсказки
|
|
117
|
+
* x - всегда зависит от положения курсора в момент наведения
|
|
118
|
+
* y - если пропс overlayChildren true, подсказка будет поверх дочерних компонентов в месте наведения,
|
|
119
|
+
* в ином случае подсказка всплывает под дочерним элементом
|
|
120
|
+
*/
|
|
121
|
+
let posX = mousePositionRef.current.x + OFFSET_X;
|
|
122
|
+
let posY = overlayChildren || mousePositionRef.current.y > childrenRect.contentY + childrenRect.contentHeight
|
|
123
|
+
? mousePositionRef.current.y + OFFSET_Y
|
|
124
|
+
: childrenRect.contentY + childrenRect.contentHeight + CONTENT_OFFSET_Y;
|
|
125
|
+
if (position === 'bottom-center' || position === 'bottom-right' || position === 'bottom-left') {
|
|
126
|
+
posY = childrenRect.contentY + childrenRect.contentHeight + CONTENT_OFFSET_Y;
|
|
127
|
+
}
|
|
128
|
+
else if (position !== 'none') {
|
|
129
|
+
posY = childrenRect.contentY - childrenRect.contentHeight - CONTENT_OFFSET_Y;
|
|
130
|
+
}
|
|
131
|
+
setCoords({
|
|
132
|
+
x: posX,
|
|
133
|
+
y: posY
|
|
134
|
+
});
|
|
135
|
+
setIsOpen(true);
|
|
136
|
+
setTimeout(() => {
|
|
137
|
+
setIsVisible(true);
|
|
138
|
+
}, 10);
|
|
139
|
+
setTimeout(() => {
|
|
140
|
+
if (tooltipElementRef.current) {
|
|
141
|
+
const tooltipWidth = tooltipElementRef.current.offsetWidth;
|
|
142
|
+
if (position === 'bottom-center' || position === 'top-center') {
|
|
143
|
+
posX = childrenRect.x + (childrenRect.width - tooltipWidth) / 2;
|
|
144
|
+
}
|
|
145
|
+
else if (position === 'bottom-right' || position === 'top-right') {
|
|
146
|
+
posX = childrenRect.contentX + childrenRect.contentWidth - tooltipWidth;
|
|
147
|
+
}
|
|
148
|
+
else if (position !== 'none') {
|
|
149
|
+
posX = childrenRect.contentX;
|
|
150
|
+
}
|
|
151
|
+
adjustToViewPort(posX, posY);
|
|
152
|
+
setCoords({
|
|
153
|
+
x: posX,
|
|
154
|
+
y: posY
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
}, 0);
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
const handleMouseEnter = (e) => {
|
|
161
|
+
updateContainerRect();
|
|
162
|
+
mousePositionRef.current = {
|
|
163
|
+
x: e.clientX,
|
|
164
|
+
y: e.clientY,
|
|
165
|
+
};
|
|
166
|
+
if (timeoutRef.current) {
|
|
167
|
+
clearTimeout(timeoutRef.current);
|
|
168
|
+
}
|
|
169
|
+
timeoutRef.current = window.setTimeout(() => {
|
|
170
|
+
updateCoords();
|
|
171
|
+
}, displayDelay);
|
|
172
|
+
};
|
|
173
|
+
const handleMouseLeave = () => {
|
|
174
|
+
if (timeoutRef.current) {
|
|
175
|
+
clearTimeout(timeoutRef.current);
|
|
176
|
+
timeoutRef.current = null;
|
|
177
|
+
}
|
|
178
|
+
setIsVisible(false);
|
|
179
|
+
setTimeout(() => {
|
|
180
|
+
setIsOpen(false);
|
|
181
|
+
}, hideDelay);
|
|
182
|
+
};
|
|
183
|
+
const handleMouseMove = (e) => {
|
|
184
|
+
mousePositionRef.current = {
|
|
185
|
+
x: e.clientX,
|
|
186
|
+
y: e.clientY,
|
|
187
|
+
};
|
|
188
|
+
if (isOpen && followCursor) {
|
|
189
|
+
updateCoords(e.clientX, e.clientY);
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
const tooltipStyles = Object.assign(Object.assign({}, style), { position: 'fixed', left: `${coords.x}px`, top: `${coords.y}px`, backgroundColor: color ? hexToRgba(color, opacity) : `rgba(0, 0, 0, ${opacity})`, zIndex: 1000 });
|
|
193
|
+
const tooltipClassNames = classNames(styles.tooltip, isVisible && styles['tooltip--visible'], className);
|
|
194
|
+
return (React.createElement(React.Fragment, null,
|
|
195
|
+
React.createElement("div", { onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onMouseMove: handleMouseMove, className: styles.wrapper, ref: childrenRef }, children),
|
|
196
|
+
isOpen && ReactDOM.createPortal(React.createElement("div", { ref: tooltipElementRef, className: tooltipClassNames, style: tooltipStyles },
|
|
197
|
+
React.createElement(Typography, { variant: textSize === 'sm' ? "Caption-Medium" : textSize === 'md' ? "Body2-Medium" : "Body1-Medium" }, label)), document.body)));
|
|
198
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
.tooltip {
|
|
2
|
+
backdrop-filter: blur(5px);
|
|
3
|
+
border-radius: 8px;
|
|
4
|
+
padding: 5px 8px;
|
|
5
|
+
width: fit-content;
|
|
6
|
+
font-family: var(--font-family-content);
|
|
7
|
+
color: white;
|
|
8
|
+
display: flex;
|
|
9
|
+
align-items: center;
|
|
10
|
+
pointer-events: none;
|
|
11
|
+
box-shadow: 0 4px 14.9px -3px rgba(0, 0, 0, 0.3);
|
|
12
|
+
opacity: 0;
|
|
13
|
+
transition: opacity 0.1s ease-out;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.tooltip--visible {
|
|
17
|
+
opacity: 1;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.wrapper {
|
|
21
|
+
width: fit-content;
|
|
22
|
+
}
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
.typography--variant-Body-Medium {
|
|
82
82
|
font-family: var(--font-family-content);
|
|
83
83
|
font-size: var(--font-size-16);
|
|
84
|
-
font-weight: var(--font-weight-
|
|
84
|
+
font-weight: var(--font-weight-medium);
|
|
85
85
|
line-height: var(--lineHeight-16);
|
|
86
86
|
letter-spacing: var(--letterSpacing);
|
|
87
87
|
text-decoration: none;
|
|
@@ -161,7 +161,7 @@
|
|
|
161
161
|
.typography--variant-Body2-Medium {
|
|
162
162
|
font-family: var(--font-family-content);
|
|
163
163
|
font-size: var(--font-size-12);
|
|
164
|
-
font-weight: var(--font-weight-
|
|
164
|
+
font-weight: var(--font-weight-medium);
|
|
165
165
|
line-height: var(--lineHeight-12);
|
|
166
166
|
letter-spacing: var(--letterSpacing);
|
|
167
167
|
text-decoration: none;
|
|
@@ -184,25 +184,25 @@
|
|
|
184
184
|
}
|
|
185
185
|
.typography--variant-Caption {
|
|
186
186
|
font-family: var(--font-family-content);
|
|
187
|
-
font-size: var(--font-size-
|
|
187
|
+
font-size: var(--font-size-10);
|
|
188
188
|
font-weight: var(--font-weight-regular);
|
|
189
|
-
line-height: var(--lineHeight-
|
|
189
|
+
line-height: var(--lineHeight-10);
|
|
190
190
|
letter-spacing: var(--letterSpacing);
|
|
191
191
|
text-decoration: none;
|
|
192
192
|
}
|
|
193
193
|
.typography--variant-Caption-Medium {
|
|
194
194
|
font-family: var(--font-family-content);
|
|
195
|
-
font-size: var(--font-size-
|
|
196
|
-
font-weight: var(--font-weight-
|
|
197
|
-
line-height: var(--lineHeight-
|
|
195
|
+
font-size: var(--font-size-10);
|
|
196
|
+
font-weight: var(--font-weight-medium);
|
|
197
|
+
line-height: var(--lineHeight-10);
|
|
198
198
|
letter-spacing: var(--letterSpacing);
|
|
199
199
|
text-decoration: none;
|
|
200
200
|
}
|
|
201
201
|
.typography--variant-Caption-Bold {
|
|
202
202
|
font-family: var(--font-family-content);
|
|
203
|
-
font-size: var(--font-size-
|
|
203
|
+
font-size: var(--font-size-10);
|
|
204
204
|
font-weight: var(--font-weight-bold);
|
|
205
|
-
line-height: var(--lineHeight-
|
|
205
|
+
line-height: var(--lineHeight-10);
|
|
206
206
|
letter-spacing: var(--letterSpacing);
|
|
207
207
|
text-decoration: none;
|
|
208
208
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -14,10 +14,15 @@ export { Tabs as Tabs } from './components/Tabs/Tabs';
|
|
|
14
14
|
export { Tag as Tag } from './components/Tag/Tag';
|
|
15
15
|
export { ToggleButton as ToggleButton } from './components/ToggleButton/ToggleButton';
|
|
16
16
|
export { Typography as Typography } from './components/Typography/Typography';
|
|
17
|
-
export {
|
|
17
|
+
export { FileItem as FileItem } from './components/FileItem/FileItem';
|
|
18
18
|
export { FileAttach as FileAttach } from './components/FileAttach/FileAttach';
|
|
19
19
|
export { Spinner as Spinner } from './components/Spinner/Spinner';
|
|
20
20
|
export { Dialog as Dialog } from './components/Dialog/Dialog';
|
|
21
21
|
export { IconButton as IconButton } from './components/IconButton/IconButton';
|
|
22
|
-
export
|
|
22
|
+
export { List as List } from './components/List/List';
|
|
23
|
+
export { ListItem as ListItem } from './components/ListItem/ListItem';
|
|
24
|
+
export { Breadcrumb as Breadcrumb } from './components/Breadcrumb/Breadcrumb';
|
|
25
|
+
export { Breadcrumbs as Breadcrumbs } from './components/Breadcrumbs/Breadcrumbs';
|
|
26
|
+
export { Tooltip as Tooltip } from './components/Tooltip/Tooltip';
|
|
27
|
+
export type { ButtonProps, InputProps, DateInputProps, TagProps, SettingTagProps, ToggleButtonProps, BaseOptions, TOptions, DropdownProps, TypographyProps, ProgressBarProps, ProgressLoaderProps, RadioProps, TabsProps, ColorPickerProps, SnackbarProps, FileItemProps, FileAttachProps, SpinnerProps, DialogProps, IconButtonProps, BaseListProps, ListProps, ListItemProps, BreadcrumbProps, BreadcrumbsProps, TooltipProps, } from './types';
|
|
23
28
|
import './fonts.css';
|
package/dist/index.js
CHANGED
|
@@ -14,9 +14,14 @@ export { Tabs as Tabs } from './components/Tabs/Tabs';
|
|
|
14
14
|
export { Tag as Tag } from './components/Tag/Tag';
|
|
15
15
|
export { ToggleButton as ToggleButton } from './components/ToggleButton/ToggleButton';
|
|
16
16
|
export { Typography as Typography } from './components/Typography/Typography';
|
|
17
|
-
export {
|
|
17
|
+
export { FileItem as FileItem } from './components/FileItem/FileItem';
|
|
18
18
|
export { FileAttach as FileAttach } from './components/FileAttach/FileAttach';
|
|
19
19
|
export { Spinner as Spinner } from './components/Spinner/Spinner';
|
|
20
20
|
export { Dialog as Dialog } from './components/Dialog/Dialog';
|
|
21
21
|
export { IconButton as IconButton } from './components/IconButton/IconButton';
|
|
22
|
+
export { List as List } from './components/List/List';
|
|
23
|
+
export { ListItem as ListItem } from './components/ListItem/ListItem';
|
|
24
|
+
export { Breadcrumb as Breadcrumb } from './components/Breadcrumb/Breadcrumb';
|
|
25
|
+
export { Breadcrumbs as Breadcrumbs } from './components/Breadcrumbs/Breadcrumbs';
|
|
26
|
+
export { Tooltip as Tooltip } from './components/Tooltip/Tooltip';
|
|
22
27
|
import './fonts.css';
|
package/dist/types/index.d.ts
CHANGED
|
@@ -278,6 +278,10 @@ export interface CheckboxProps {
|
|
|
278
278
|
size?: 'sm' | 'md';
|
|
279
279
|
/** Текст лейбла */
|
|
280
280
|
label?: string;
|
|
281
|
+
/** Цвет чекбока */
|
|
282
|
+
color?: string;
|
|
283
|
+
/** Заливка */
|
|
284
|
+
filled?: boolean;
|
|
281
285
|
}
|
|
282
286
|
export interface RadioProps {
|
|
283
287
|
/** Значение */
|
|
@@ -348,7 +352,7 @@ export type SnackbarProps = {
|
|
|
348
352
|
/** Функция обработки закрытия сообщения */
|
|
349
353
|
onClose?: () => void;
|
|
350
354
|
};
|
|
351
|
-
export interface
|
|
355
|
+
export interface FileItemProps {
|
|
352
356
|
/** Название файла */
|
|
353
357
|
name?: string;
|
|
354
358
|
/** Размер файла */
|
|
@@ -357,8 +361,12 @@ export interface LoaderProps {
|
|
|
357
361
|
loading?: boolean;
|
|
358
362
|
/** Текст ошибки загрузки файла */
|
|
359
363
|
error?: string;
|
|
360
|
-
/** Функция обработки */
|
|
361
|
-
|
|
364
|
+
/** Функция обработки скачивания файла */
|
|
365
|
+
onDownload?: () => void;
|
|
366
|
+
/** Функция обработки удаления файла */
|
|
367
|
+
onDelete?: () => void;
|
|
368
|
+
/** Стили передаваемые напрямую */
|
|
369
|
+
style?: CSSProperties;
|
|
362
370
|
}
|
|
363
371
|
export interface FileAttachProps {
|
|
364
372
|
/** Максимальный размер файла */
|
|
@@ -369,14 +377,16 @@ export interface FileAttachProps {
|
|
|
369
377
|
acceptedFormats?: Accept;
|
|
370
378
|
/**Добавленные файлы */
|
|
371
379
|
addedFiles: File[];
|
|
372
|
-
|
|
380
|
+
/**Сосотояние для добавления файлов */
|
|
373
381
|
setAddedFiles: (addedFiles: File[]) => void;
|
|
382
|
+
/** Функция обработки скачивания файла */
|
|
383
|
+
onDownload?: () => void;
|
|
374
384
|
/**Заблокировано добавление файлов*/
|
|
375
385
|
disabled?: boolean;
|
|
376
386
|
/** Дополнительный класс */
|
|
377
387
|
className?: string;
|
|
378
388
|
/** Стили передаваемые напрямую */
|
|
379
|
-
style?: CSSProperties;
|
|
389
|
+
style?: React.CSSProperties;
|
|
380
390
|
}
|
|
381
391
|
export interface DialogProps {
|
|
382
392
|
/** Флаг открытия окна */
|
|
@@ -409,4 +419,84 @@ export interface IconButtonProps {
|
|
|
409
419
|
onClick: () => void;
|
|
410
420
|
/** Дочерние элементы */
|
|
411
421
|
children?: ReactNode;
|
|
422
|
+
/** Дополнительный класс */
|
|
423
|
+
className?: string;
|
|
424
|
+
}
|
|
425
|
+
export interface BaseListProps {
|
|
426
|
+
/** Идентификатор */
|
|
427
|
+
id?: string;
|
|
428
|
+
/** Стиль элемента списка */
|
|
429
|
+
style?: CSSProperties;
|
|
430
|
+
/** Дополнительный класс */
|
|
431
|
+
className?: string;
|
|
432
|
+
/** Обработчик клика */
|
|
433
|
+
onClick?: () => void;
|
|
434
|
+
/** Обработчик выбора чекбокса */
|
|
435
|
+
onCheck?: (activeId: string | string[], isChecked: boolean) => void;
|
|
436
|
+
/** Заблокированный чекбокс/RadioButton */
|
|
437
|
+
disabled?: boolean;
|
|
438
|
+
/** Кастомный цвет чекбокса */
|
|
439
|
+
checkboxColor?: string;
|
|
440
|
+
/** Заливка чекбокса */
|
|
441
|
+
checkboxFilled?: boolean;
|
|
442
|
+
/** Обработчик выбора RadioButton */
|
|
443
|
+
onRadioSelect?: (id: string) => void;
|
|
444
|
+
/** Активный чекбокс */
|
|
445
|
+
checked?: boolean;
|
|
446
|
+
/** Активный чекбокс родительского компонента */
|
|
447
|
+
parentChecked?: boolean;
|
|
448
|
+
/** Выбранный RadioButton */
|
|
449
|
+
selected?: boolean;
|
|
450
|
+
/** Отображаемый текст */
|
|
451
|
+
label?: string;
|
|
452
|
+
/** Добавлен чекбокс */
|
|
453
|
+
withCheckbox?: boolean;
|
|
454
|
+
/** Добавлен RadioButton */
|
|
455
|
+
withRadioButton?: boolean;
|
|
456
|
+
/** Кастомный буллит */
|
|
457
|
+
customBullet?: React.ReactNode;
|
|
458
|
+
/** Стиль кастомного буллита */
|
|
459
|
+
bulletClassName?: string;
|
|
460
|
+
}
|
|
461
|
+
export interface ListItemProps extends BaseListProps {
|
|
462
|
+
/** Дочерние элементы */
|
|
463
|
+
children?: ReactNode;
|
|
464
|
+
}
|
|
465
|
+
export interface ListProps extends BaseListProps {
|
|
466
|
+
/** Дочерние элементы */
|
|
467
|
+
children: React.ReactElement<ListItemProps> | React.ReactElement<ListItemProps>[];
|
|
468
|
+
/** Возможность раскрытия списка */
|
|
469
|
+
collapsible?: boolean;
|
|
470
|
+
/** Кастомный буллит дочернего компонента */
|
|
471
|
+
customItemBullet?: React.ReactNode;
|
|
472
|
+
/** Внешний компонент без буллитов/чекбоксов */
|
|
473
|
+
isHeader?: boolean;
|
|
474
|
+
/** Раскрытый список */
|
|
475
|
+
open?: boolean;
|
|
476
|
+
}
|
|
477
|
+
export interface TooltipProps {
|
|
478
|
+
/** Текст подсказки */
|
|
479
|
+
label: string;
|
|
480
|
+
/** Дочерние элементы */
|
|
481
|
+
children: React.ReactNode;
|
|
482
|
+
/** Дополнительный класс */
|
|
483
|
+
className?: string;
|
|
484
|
+
/** Стиль подсказки */
|
|
485
|
+
style?: CSSProperties;
|
|
486
|
+
/** Положение подсказки */
|
|
487
|
+
overlayChildren?: boolean;
|
|
488
|
+
/** Размер текста */
|
|
489
|
+
textSize?: 'sm' | 'md' | 'lg';
|
|
490
|
+
/** Позиция подсказки */
|
|
491
|
+
position?: 'none' | 'bottom-center' | 'bottom-right' | 'bottom-left' | 'top-center' | 'top-right' | 'top-left';
|
|
492
|
+
/** Время, через которое будет показана подсказка */
|
|
493
|
+
displayDelay?: number;
|
|
494
|
+
/** Время, через которое будет скрыта подсказка */
|
|
495
|
+
hideDelay?: number;
|
|
496
|
+
/** Прозрачность подсказки (значение от 0 до 1) */
|
|
497
|
+
opacity?: number;
|
|
498
|
+
/** Цвет подсказки */
|
|
499
|
+
color?: string;
|
|
500
|
+
/** Подсказка, следующая за курсором */
|
|
501
|
+
followCursor?: boolean;
|
|
412
502
|
}
|
package/package.json
CHANGED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import styles from './Loader.module.css';
|
|
3
|
-
import { Typography } from '../Typography/Typography';
|
|
4
|
-
import { IconFile } from '../../Icons/IconFile/IconFile';
|
|
5
|
-
import { ProgressBar } from '../ProgressBar/ProgressBar';
|
|
6
|
-
export const Loader = ({ name, size = 0, loading = false, error = '', onClick }) => {
|
|
7
|
-
return (React.createElement("div", { className: `${styles['loader']} ${error ? styles['error'] : ''}` },
|
|
8
|
-
React.createElement("div", { className: styles['loaderFile'] },
|
|
9
|
-
React.createElement("div", { className: styles['loaderInfo'] },
|
|
10
|
-
React.createElement("div", { className: styles['loaderIcon'] },
|
|
11
|
-
React.createElement(IconFile, { htmlColor: 'var(--icons-grey)' })),
|
|
12
|
-
React.createElement("div", { className: styles['loaderName'] },
|
|
13
|
-
React.createElement(Typography, { variant: "Body1-Medium", color: "var(--text-dark)" }, name),
|
|
14
|
-
size !== 0 && (React.createElement(Typography, { variant: "Caption", color: "var(--grey-medium)" }, `${(size / 1024).toFixed(1)} кБ`)))),
|
|
15
|
-
React.createElement("button", { type: "button", "aria-label": "\u0417\u0430\u043A\u0440\u044B\u0442\u044C", title: "\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0444\u0430\u0439\u043B", onClick: onClick })),
|
|
16
|
-
loading && React.createElement(ProgressBar, { animated: true, size: "sm", value: 100 }),
|
|
17
|
-
error && (React.createElement(Typography, { variant: "Caption", color: "var(--error-main)" }, error))));
|
|
18
|
-
};
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
.loader {
|
|
3
|
-
display: flex;
|
|
4
|
-
flex-direction: column;
|
|
5
|
-
gap: 5px;
|
|
6
|
-
justify-content: space-between;
|
|
7
|
-
|
|
8
|
-
padding: 10px 15px;
|
|
9
|
-
border: 1px solid var(--info-secondary);
|
|
10
|
-
border-radius: 10px;
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
.error {
|
|
14
|
-
border-color: var(--error-main);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
.loaderFile{
|
|
18
|
-
display: flex;
|
|
19
|
-
flex-direction: row;
|
|
20
|
-
align-items: center;
|
|
21
|
-
gap: 5px;
|
|
22
|
-
}
|
|
23
|
-
.loaderInfo {
|
|
24
|
-
display: flex;
|
|
25
|
-
flex-direction: row;
|
|
26
|
-
gap: 5px;
|
|
27
|
-
flex-grow: 1;
|
|
28
|
-
align-items: flex-start;
|
|
29
|
-
overflow: hidden;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
.loaderIcon {
|
|
33
|
-
flex-shrink: 0
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
.loaderName {
|
|
37
|
-
display: flex;
|
|
38
|
-
flex-direction: column;
|
|
39
|
-
flex-grow: 1;
|
|
40
|
-
align-items: flex-start;
|
|
41
|
-
overflow: auto;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
.loaderButton{
|
|
45
|
-
position: absolute;
|
|
46
|
-
left: 50%;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
.loader button[aria-label="Закрыть"] {
|
|
50
|
-
background: none;
|
|
51
|
-
border: none;
|
|
52
|
-
padding: 0;
|
|
53
|
-
cursor: pointer;
|
|
54
|
-
position: relative;
|
|
55
|
-
width: 10px;
|
|
56
|
-
height: 10px;
|
|
57
|
-
flex-shrink: 0
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
.loader button[aria-label="Закрыть"]::before,
|
|
61
|
-
.loader button[aria-label="Закрыть"]::after {
|
|
62
|
-
content: '';
|
|
63
|
-
position: absolute;
|
|
64
|
-
top: 50%;
|
|
65
|
-
left: 50%;
|
|
66
|
-
transform: translate(-50%, -50%) rotate(45deg);
|
|
67
|
-
height: 1px;
|
|
68
|
-
width: 100%;
|
|
69
|
-
background-color: var(--icons-grey);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
.loader button[aria-label="Закрыть"]::after {
|
|
73
|
-
transform: translate(-50%, -50%) rotate(-45deg);
|
|
74
|
-
}
|
|
75
|
-
|