@astral/ui 4.36.1 → 4.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/Autocomplete/Autocomplete.d.ts +1 -1
- package/components/Autocomplete/Autocomplete.js +53 -15
- package/components/Autocomplete/constants.d.ts +6 -0
- package/components/Autocomplete/constants.js +7 -0
- package/components/Autocomplete/styles.js +15 -1
- package/components/Autocomplete/useLogic/useLogic.d.ts +2 -1
- package/components/Autocomplete/useLogic/useLogic.js +11 -2
- package/components/TagsList/Tag/Tag.d.ts +1 -1
- package/components/TagsList/Tag/constants.d.ts +1 -0
- package/components/TagsList/Tag/constants.js +1 -0
- package/components/TagsList/Tag/index.d.ts +1 -0
- package/components/TagsList/Tag/index.js +1 -0
- package/components/TagsList/Tag/styles.js +2 -0
- package/components/TagsList/TagsList.js +6 -6
- package/components/TagsList/constants.d.ts +2 -0
- package/components/TagsList/constants.js +2 -0
- package/components/TagsList/styles.js +5 -1
- package/components/TagsList/types.d.ts +14 -5
- package/components/TagsList/useLogic/useLogic.d.ts +5 -5
- package/components/TagsList/useLogic/useLogic.js +70 -110
- package/components/TagsList/utils/calculateVisibleTagsCount/calculateVisibleTagsCount.d.ts +6 -0
- package/components/TagsList/utils/calculateVisibleTagsCount/calculateVisibleTagsCount.js +35 -0
- package/components/TagsList/utils/calculateVisibleTagsCount/index.d.ts +1 -0
- package/components/TagsList/utils/calculateVisibleTagsCount/index.js +1 -0
- package/components/TagsList/utils/getAvailableWidth/getAvailableWidth.d.ts +1 -0
- package/components/TagsList/utils/getAvailableWidth/getAvailableWidth.js +7 -0
- package/components/TagsList/utils/getAvailableWidth/index.d.ts +1 -0
- package/components/TagsList/utils/getAvailableWidth/index.js +1 -0
- package/components/TagsList/utils/getKey/getKey.d.ts +1 -1
- package/components/TagsList/utils/getKey/getKey.js +6 -3
- package/components/TagsList/utils/getTagWidth/getTagWidth.d.ts +2 -0
- package/components/TagsList/utils/getTagWidth/getTagWidth.js +21 -0
- package/components/TagsList/utils/getTagWidth/index.d.ts +1 -0
- package/components/TagsList/utils/getTagWidth/index.js +1 -0
- package/components/TagsList/utils/index.d.ts +3 -0
- package/components/TagsList/utils/index.js +3 -0
- package/components/TextField/TextField.js +6 -5
- package/components/TextField/constants.d.ts +1 -0
- package/components/TextField/constants.js +1 -0
- package/components/TextField/styles.js +4 -0
- package/components/TreeLikeAsyncAutocomplete/Input/Input.js +1 -1
- package/node/components/Autocomplete/Autocomplete.d.ts +1 -1
- package/node/components/Autocomplete/Autocomplete.js +51 -13
- package/node/components/Autocomplete/constants.d.ts +6 -0
- package/node/components/Autocomplete/constants.js +8 -1
- package/node/components/Autocomplete/styles.js +15 -1
- package/node/components/Autocomplete/useLogic/useLogic.d.ts +2 -1
- package/node/components/Autocomplete/useLogic/useLogic.js +10 -1
- package/node/components/TagsList/Tag/Tag.d.ts +1 -1
- package/node/components/TagsList/Tag/constants.d.ts +1 -0
- package/node/components/TagsList/Tag/constants.js +4 -0
- package/node/components/TagsList/Tag/index.d.ts +1 -0
- package/node/components/TagsList/Tag/index.js +1 -0
- package/node/components/TagsList/Tag/styles.js +2 -0
- package/node/components/TagsList/TagsList.js +6 -6
- package/node/components/TagsList/constants.d.ts +2 -0
- package/node/components/TagsList/constants.js +5 -0
- package/node/components/TagsList/styles.js +5 -1
- package/node/components/TagsList/types.d.ts +14 -5
- package/node/components/TagsList/useLogic/useLogic.d.ts +5 -5
- package/node/components/TagsList/useLogic/useLogic.js +70 -110
- package/node/components/TagsList/utils/calculateVisibleTagsCount/calculateVisibleTagsCount.d.ts +6 -0
- package/node/components/TagsList/utils/calculateVisibleTagsCount/calculateVisibleTagsCount.js +39 -0
- package/node/components/TagsList/utils/calculateVisibleTagsCount/index.d.ts +1 -0
- package/node/components/TagsList/utils/calculateVisibleTagsCount/index.js +5 -0
- package/node/components/TagsList/utils/getAvailableWidth/getAvailableWidth.d.ts +1 -0
- package/node/components/TagsList/utils/getAvailableWidth/getAvailableWidth.js +11 -0
- package/node/components/TagsList/utils/getAvailableWidth/index.d.ts +1 -0
- package/node/components/TagsList/utils/getAvailableWidth/index.js +5 -0
- package/node/components/TagsList/utils/getKey/getKey.d.ts +1 -1
- package/node/components/TagsList/utils/getKey/getKey.js +6 -3
- package/node/components/TagsList/utils/getTagWidth/getTagWidth.d.ts +2 -0
- package/node/components/TagsList/utils/getTagWidth/getTagWidth.js +25 -0
- package/node/components/TagsList/utils/getTagWidth/index.d.ts +1 -0
- package/node/components/TagsList/{public.js → utils/getTagWidth/index.js} +1 -2
- package/node/components/TagsList/utils/index.d.ts +3 -0
- package/node/components/TagsList/utils/index.js +7 -1
- package/node/components/TextField/TextField.js +6 -5
- package/node/components/TextField/constants.d.ts +1 -0
- package/node/components/TextField/constants.js +1 -0
- package/node/components/TextField/styles.js +4 -0
- package/node/components/TreeLikeAsyncAutocomplete/Input/Input.js +1 -1
- package/package.json +1 -1
- package/components/TagsList/public.d.ts +0 -2
- package/components/TagsList/public.js +0 -2
- package/node/components/TagsList/public.d.ts +0 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const getAvailableWidth: (containerEl: HTMLElement, reservedWidth?: number) => number;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export const getAvailableWidth = (containerEl, reservedWidth = 0) => {
|
|
2
|
+
const containerWidth = containerEl.clientWidth;
|
|
3
|
+
const paddingLeft = parseFloat(getComputedStyle(containerEl).paddingLeft);
|
|
4
|
+
const paddingRight = parseFloat(getComputedStyle(containerEl).paddingRight);
|
|
5
|
+
const availableWidth = containerWidth - paddingLeft - paddingRight - reservedWidth;
|
|
6
|
+
return availableWidth;
|
|
7
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { getAvailableWidth } from './getAvailableWidth';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { getAvailableWidth } from './getAvailableWidth';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { TagValue } from '../../types';
|
|
2
|
-
export declare const getKey: (option:
|
|
2
|
+
export declare const getKey: <TData extends TagValue>(option: TData, keyId: string | undefined, getOptionLabel: (tagOption: TData) => string | number) => string;
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
export const getKey = (option, keyId) => {
|
|
1
|
+
export const getKey = (option, keyId, getOptionLabel) => {
|
|
2
2
|
if (typeof option === 'string') {
|
|
3
3
|
return option;
|
|
4
4
|
}
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
if (keyId) {
|
|
6
|
+
const key = option[keyId];
|
|
7
|
+
return typeof key === 'number' ? key.toString() : key;
|
|
8
|
+
}
|
|
9
|
+
return getOptionLabel(option).toString();
|
|
7
10
|
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { MAX_TAG_WIDTH } from '../../Tag';
|
|
2
|
+
export const getTagWidth = (label, theme, isCounter = false) => {
|
|
3
|
+
/** 16px иконка и 2px padding */
|
|
4
|
+
const DELETE_ICON_WIDTH = 18;
|
|
5
|
+
const el = document.createElement('div');
|
|
6
|
+
el.textContent = label.toString();
|
|
7
|
+
el.style.visibility = 'hidden';
|
|
8
|
+
el.style.position = 'absolute';
|
|
9
|
+
el.style.display = 'inline-flex';
|
|
10
|
+
el.style.whiteSpace = 'nowrap';
|
|
11
|
+
el.style.padding = theme.spacing(0, 2);
|
|
12
|
+
el.style.paddingLeft = theme.spacing(2);
|
|
13
|
+
el.style.paddingRight = isCounter ? theme.spacing(2) : theme.microSpacing(1);
|
|
14
|
+
el.style.boxSizing = 'border-box';
|
|
15
|
+
document.body.appendChild(el);
|
|
16
|
+
const width = isCounter
|
|
17
|
+
? el.getBoundingClientRect().width
|
|
18
|
+
: el.getBoundingClientRect().width + DELETE_ICON_WIDTH;
|
|
19
|
+
document.body.removeChild(el);
|
|
20
|
+
return Math.ceil(Math.min(width, parseInt(MAX_TAG_WIDTH, 10)));
|
|
21
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './getTagWidth';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './getTagWidth';
|
|
@@ -1,2 +1,5 @@
|
|
|
1
1
|
export { getElementByText } from './getElementByText';
|
|
2
2
|
export { getKey } from './getKey';
|
|
3
|
+
export { getTagWidth } from './getTagWidth';
|
|
4
|
+
export { getAvailableWidth } from './getAvailableWidth';
|
|
5
|
+
export { calculateVisibleTagsCount } from './calculateVisibleTagsCount';
|
|
@@ -1,2 +1,5 @@
|
|
|
1
1
|
export { getElementByText } from './getElementByText';
|
|
2
2
|
export { getKey } from './getKey';
|
|
3
|
+
export { getTagWidth } from './getTagWidth';
|
|
4
|
+
export { getAvailableWidth } from './getAvailableWidth';
|
|
5
|
+
export { calculateVisibleTagsCount } from './calculateVisibleTagsCount';
|
|
@@ -4,7 +4,7 @@ import { FormHelperTextContent } from '../FormHelperText';
|
|
|
4
4
|
import { classNames } from '../utils/classNames';
|
|
5
5
|
import { textFieldClassnames } from './constants';
|
|
6
6
|
import { StyledTextField } from './styles';
|
|
7
|
-
export const TextField = forwardRef(({ success, error, helperText: helperTextProp, fullWidth = false, startAdornment, endAdornment, inputProps, InputProps, maxLength, trimmed = true, onBlur, hideHelperText = false, className, ...props }, ref) => {
|
|
7
|
+
export const TextField = forwardRef(({ success, error, helperText: helperTextProp, fullWidth = false, startAdornment, endAdornment, inputProps, InputProps, maxLength, trimmed = true, onBlur, hideHelperText = false, className, disabled, ...props }, ref) => {
|
|
8
8
|
const color = useMemo(() => {
|
|
9
9
|
if (success) {
|
|
10
10
|
return 'success';
|
|
@@ -37,9 +37,10 @@ export const TextField = forwardRef(({ success, error, helperText: helperTextPro
|
|
|
37
37
|
}
|
|
38
38
|
onBlur?.(event);
|
|
39
39
|
};
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
const classnames = useMemo(() => classNames(className, {
|
|
41
|
+
[textFieldClassnames.hideHelperText]: hideHelperText,
|
|
42
|
+
[textFieldClassnames.disabled]: disabled,
|
|
43
|
+
}), [className, hideHelperText, disabled]);
|
|
43
44
|
return (_jsx(StyledTextField, { ref: ref, variant: "outlined", fullWidth: fullWidth, error: error, color: color, helperText: helperText, InputProps: {
|
|
44
45
|
startAdornment,
|
|
45
46
|
endAdornment,
|
|
@@ -47,5 +48,5 @@ export const TextField = forwardRef(({ success, error, helperText: helperTextPro
|
|
|
47
48
|
}, inputProps: {
|
|
48
49
|
maxLength,
|
|
49
50
|
...inputProps,
|
|
50
|
-
}, onBlur: handleBlur, className:
|
|
51
|
+
}, onBlur: handleBlur, className: classnames, disabled: disabled, ...props }));
|
|
51
52
|
});
|
|
@@ -9,7 +9,7 @@ import { IconWrapper, StyledTagsList, StyledTextField } from './styles';
|
|
|
9
9
|
import { useLogic } from './useLogic';
|
|
10
10
|
const ClearButton = ({ disabled, onClick }) => (_jsx(IconButton, { variant: "text", color: "grey", disabled: disabled, onClick: onClick, title: CLEAR_TEXT, "aria-label": CLEAR_TEXT, children: _jsx(CrossOutlineMd, {}) }));
|
|
11
11
|
export const Input = forwardRef(({ disabled, onChange: propsOnChange, value, inputRef, hideHelperText = false, onClick, isLoading, ...restProps }, forwardedRef) => {
|
|
12
|
-
const { isVisibleClearButton,
|
|
12
|
+
const { isVisibleClearButton, isVisibleTagsList, onChange, textFieldProps, onClearAll, } = useLogic({
|
|
13
13
|
inputRef,
|
|
14
14
|
value,
|
|
15
15
|
onChange: propsOnChange,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
2
|
import { type AutocompleteRenderInputParams } from './types';
|
|
3
|
-
export declare const Autocomplete: <TAutocompleteValueProps, TMultiple extends boolean, TDisableClearable extends boolean, TFreeSolo extends boolean>(props: Omit<import("..").WithoutEmotionSpecific<import("@mui/material
|
|
3
|
+
export declare const Autocomplete: <TAutocompleteValueProps, TMultiple extends boolean, TDisableClearable extends boolean, TFreeSolo extends boolean>(props: Omit<import("..").WithoutEmotionSpecific<import("@mui/material").AutocompleteProps<TAutocompleteValueProps, TMultiple, TDisableClearable, TFreeSolo, "div">>, "size" | "clearText" | "closeText" | "noOptionsText" | "openText" | "renderInput"> & Pick<import("../TextField").TextFieldProps, "label" | "success" | "error" | "placeholder" | "required" | "inputRef" | "helperText" | "inputProps"> & {
|
|
4
4
|
renderInput?: ((props: Omit<import("..").WithoutEmotionSpecific<import("@mui/material").TextFieldProps>, "color" | "select" | "margin" | "variant" | "multiline" | "SelectProps"> & {
|
|
5
5
|
success?: boolean | undefined;
|
|
6
6
|
startAdornment?: import("react").ReactNode;
|
|
@@ -14,7 +14,7 @@ const Checkbox_1 = require("../Checkbox");
|
|
|
14
14
|
const forwardRefWithGeneric_1 = require("../forwardRefWithGeneric");
|
|
15
15
|
const Loader_1 = require("../Loader");
|
|
16
16
|
const OverflowTypography_1 = require("../OverflowTypography");
|
|
17
|
-
const
|
|
17
|
+
const TagsList_1 = require("../TagsList");
|
|
18
18
|
const TextField_1 = require("../TextField");
|
|
19
19
|
const classNames_1 = require("../utils/classNames");
|
|
20
20
|
const constants_1 = require("./constants");
|
|
@@ -22,14 +22,51 @@ const styles_1 = require("./styles");
|
|
|
22
22
|
const useLogic_1 = require("./useLogic");
|
|
23
23
|
const AutocompleteInner = (props, ref) => {
|
|
24
24
|
const { isValueEmpty, isPopperVisible, autocompleteProps } = (0, useLogic_1.useLogic)(props);
|
|
25
|
-
const
|
|
25
|
+
const inputBaseRef = (0, react_1.useRef)(null);
|
|
26
|
+
const { required, success, error, label, getOptionLabel, helperText, inputRef, multiple, size = 'medium', placeholder = constants_1.DEFAULT_PLACEHOLDER, overflowOption, closeText = 'Закрыть', openText = 'Открыть', clearText = 'Очистить', loadingText = (0, jsx_runtime_1.jsx)(Loader_1.Loader, {}), isLoadedDataError, loadedDataError, noOptionsText, autoHighlight, renderInput: externalRenderInput, renderTags: externalRenderTags, renderOption: externalRenderOption, inputProps, hideHelperText = false, loading, value, onChange, ...restProps } = props;
|
|
26
27
|
const renderInput = (0, react_1.useCallback)((inputParams) => {
|
|
28
|
+
const createStartAdornment = () => {
|
|
29
|
+
if (!multiple || !Array.isArray(value)) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
const tagsListElement = ((0, jsx_runtime_1.jsx)(TagsList_1.TagsList, { data: value, getOptionLabel: (option) => getOptionLabel?.(option) ??
|
|
33
|
+
option.toString(), inputContainerRef: inputBaseRef, reservedWidth: constants_1.INPUT_MIN_WIDTH, onChange: (tagValues) => {
|
|
34
|
+
if (!onChange) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const syntheticEvent = {
|
|
38
|
+
type: 'change',
|
|
39
|
+
target: { value: tagValues },
|
|
40
|
+
currentTarget: { value: tagValues },
|
|
41
|
+
};
|
|
42
|
+
const reason = 'removeOption';
|
|
43
|
+
onChange(syntheticEvent, tagValues, reason);
|
|
44
|
+
} }));
|
|
45
|
+
return tagsListElement;
|
|
46
|
+
};
|
|
27
47
|
const generalInputParams = {
|
|
28
48
|
...inputParams,
|
|
29
49
|
inputProps: {
|
|
30
50
|
...inputParams.inputProps,
|
|
31
51
|
className: (0, classNames_1.classNames)(inputParams?.inputProps?.className, inputProps?.className),
|
|
32
52
|
},
|
|
53
|
+
InputProps: {
|
|
54
|
+
...inputParams.InputProps,
|
|
55
|
+
ref: (element) => {
|
|
56
|
+
inputBaseRef.current = element;
|
|
57
|
+
const orig = inputParams.InputProps?.ref;
|
|
58
|
+
if (typeof orig === 'function') {
|
|
59
|
+
orig(element);
|
|
60
|
+
}
|
|
61
|
+
else if (orig) {
|
|
62
|
+
orig.current = element;
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
// Если есть externalRenderTags, используем renderTags(mui использует inputParams.InputProps?.startAdornment)
|
|
66
|
+
startAdornment: externalRenderTags
|
|
67
|
+
? inputParams.InputProps?.startAdornment
|
|
68
|
+
: createStartAdornment(),
|
|
69
|
+
},
|
|
33
70
|
inputRef,
|
|
34
71
|
required,
|
|
35
72
|
placeholder: isValueEmpty ? placeholder : '',
|
|
@@ -46,7 +83,9 @@ const AutocompleteInner = (props, ref) => {
|
|
|
46
83
|
return (0, jsx_runtime_1.jsx)(TextField_1.TextField, { ...generalInputParams });
|
|
47
84
|
}, [
|
|
48
85
|
isValueEmpty,
|
|
86
|
+
value,
|
|
49
87
|
externalRenderInput,
|
|
88
|
+
externalRenderTags,
|
|
50
89
|
inputRef,
|
|
51
90
|
required,
|
|
52
91
|
placeholder,
|
|
@@ -56,6 +95,9 @@ const AutocompleteInner = (props, ref) => {
|
|
|
56
95
|
helperText,
|
|
57
96
|
size,
|
|
58
97
|
hideHelperText,
|
|
98
|
+
multiple,
|
|
99
|
+
getOptionLabel,
|
|
100
|
+
onChange,
|
|
59
101
|
]);
|
|
60
102
|
const renderOption = (0, react_1.useCallback)((optionProps, option, optionState, ownerState) => {
|
|
61
103
|
if (externalRenderOption) {
|
|
@@ -65,26 +107,22 @@ const AutocompleteInner = (props, ref) => {
|
|
|
65
107
|
const { key, ...restOptionProps } = optionProps;
|
|
66
108
|
return ((0, jsx_runtime_1.jsxs)(styles_1.StyledMenuItem, { selected: isSelected, ...restOptionProps, children: [multiple && ((0, jsx_runtime_1.jsx)(ListItemIcon_1.default, { children: (0, jsx_runtime_1.jsx)(Checkbox_1.Checkbox, { role: "menuitemcheckbox", checked: isSelected }) })), (0, jsx_runtime_1.jsx)(OverflowTypography_1.OverflowTypography, { rowsCount: constants_1.DEFAULT_AUTOCOMPLETE_ELEMENT_ROWS_COUNT, ...overflowOption, children: optionProps.key })] }, key));
|
|
67
109
|
}, [multiple, overflowOption, externalRenderOption]);
|
|
68
|
-
const renderTags = (0, react_1.useCallback)((tags, getTagProps, ownerSate) => {
|
|
69
|
-
if (externalRenderTags) {
|
|
70
|
-
return externalRenderTags(tags, getTagProps, ownerSate);
|
|
71
|
-
}
|
|
72
|
-
return tags.map((tag, index) => {
|
|
73
|
-
const title = getOptionLabel?.(tag) || '';
|
|
74
|
-
const { key, ...tagProps } = getTagProps({ index });
|
|
75
|
-
return ((0, jsx_runtime_1.jsx)(Tag_1.Tag, { variant: "light", color: "grey", label: title, ...tagProps }, key));
|
|
76
|
-
});
|
|
77
|
-
}, [getOptionLabel, externalRenderTags]);
|
|
78
110
|
const renderPopper = (0, react_1.useCallback)((popperProps) => {
|
|
79
111
|
if (!isPopperVisible) {
|
|
80
112
|
return null;
|
|
81
113
|
}
|
|
82
114
|
return (0, jsx_runtime_1.jsx)(Popper_1.default, { ...popperProps });
|
|
83
115
|
}, [isPopperVisible]);
|
|
116
|
+
const renderTags = (0, react_1.useCallback)((tags, getTagProps, ownerState) => {
|
|
117
|
+
if (externalRenderTags) {
|
|
118
|
+
return externalRenderTags(tags, getTagProps, ownerState);
|
|
119
|
+
}
|
|
120
|
+
return null;
|
|
121
|
+
}, [externalRenderTags]);
|
|
84
122
|
return ((0, jsx_runtime_1.jsx)(styles_1.StyledAutocomplete, { ...restProps, ref: ref, size: size, clearText: clearText, closeText: !loading ? closeText : '', openText: !loading ? openText : '', loadingText: loadingText, multiple: multiple, disableCloseOnSelect: multiple, clearIcon: (0, jsx_runtime_1.jsx)(CrossOutlineMd_1.CrossOutlineMd, {}), loading: loading, popupIcon: loading ? (0, jsx_runtime_1.jsx)(Loader_1.Loader, { color: "primary", size: "small" }) : (0, jsx_runtime_1.jsx)(DownOutlineMd_1.DownOutlineMd, {}), forcePopupIcon: true, slotProps: {
|
|
85
123
|
popper: {
|
|
86
124
|
component: renderPopper,
|
|
87
125
|
},
|
|
88
|
-
}, getOptionLabel: getOptionLabel, renderInput: renderInput, renderTags: renderTags, renderOption: renderOption, ...autocompleteProps }));
|
|
126
|
+
}, getOptionLabel: getOptionLabel, renderInput: renderInput, renderTags: renderTags, renderOption: renderOption, value: value, onChange: onChange, ...autocompleteProps }));
|
|
89
127
|
};
|
|
90
128
|
exports.Autocomplete = (0, forwardRefWithGeneric_1.forwardRefWithGeneric)(AutocompleteInner);
|
|
@@ -1,2 +1,8 @@
|
|
|
1
1
|
export declare const DEFAULT_AUTOCOMPLETE_ELEMENT_ROWS_COUNT = 2;
|
|
2
|
+
export declare const INPUT_MIN_WIDTH = 110;
|
|
2
3
|
export declare const DEFAULT_PLACEHOLDER = "\u041D\u0430\u0447\u043D\u0438\u0442\u0435 \u0432\u0432\u043E\u0434\u0438\u0442\u044C \u0434\u043B\u044F \u043F\u043E\u0438\u0441\u043A\u0430";
|
|
4
|
+
export declare const autocompleteClassnames: {
|
|
5
|
+
root: string;
|
|
6
|
+
multiple: string;
|
|
7
|
+
emptyValue: string;
|
|
8
|
+
};
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DEFAULT_PLACEHOLDER = exports.DEFAULT_AUTOCOMPLETE_ELEMENT_ROWS_COUNT = void 0;
|
|
3
|
+
exports.autocompleteClassnames = exports.DEFAULT_PLACEHOLDER = exports.INPUT_MIN_WIDTH = exports.DEFAULT_AUTOCOMPLETE_ELEMENT_ROWS_COUNT = void 0;
|
|
4
|
+
const createUIKitClassname_1 = require("../utils/createUIKitClassname");
|
|
4
5
|
exports.DEFAULT_AUTOCOMPLETE_ELEMENT_ROWS_COUNT = 2;
|
|
6
|
+
exports.INPUT_MIN_WIDTH = 110;
|
|
5
7
|
exports.DEFAULT_PLACEHOLDER = 'Начните вводить для поиска';
|
|
8
|
+
exports.autocompleteClassnames = {
|
|
9
|
+
root: (0, createUIKitClassname_1.createUIKitClassname)('autocomplete'),
|
|
10
|
+
multiple: (0, createUIKitClassname_1.createUIKitClassname)('autocomplete_multiple'),
|
|
11
|
+
emptyValue: (0, createUIKitClassname_1.createUIKitClassname)('autocomplete_empty-value'),
|
|
12
|
+
};
|
|
@@ -31,6 +31,7 @@ const InputBase_1 = require("@mui/material/InputBase");
|
|
|
31
31
|
const MenuItem_1 = require("../MenuItem");
|
|
32
32
|
const SvgIcon_1 = require("../SvgIcon");
|
|
33
33
|
const styled_1 = require("../styled");
|
|
34
|
+
const constants_1 = require("./constants");
|
|
34
35
|
exports.StyledMenuItem = (0, styled_1.styled)(MenuItem_1.MenuItem) `
|
|
35
36
|
max-height: ${({ theme }) => theme.spacing(13)};
|
|
36
37
|
|
|
@@ -49,5 +50,18 @@ exports.StyledAutocomplete = (0, styled_1.styled)(Autocomplete_1.default) `
|
|
|
49
50
|
|
|
50
51
|
& .${Autocomplete_1.autocompleteClasses.endAdornment} .${IconButton_1.iconButtonClasses.root}:hover {
|
|
51
52
|
background-color: ${({ loading, theme }) => (loading ? 'transparent' : theme.palette.grey[100])};
|
|
52
|
-
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
&:not(.${constants_1.autocompleteClassnames.emptyValue}) .${InputBase_1.inputBaseClasses.root} {
|
|
56
|
+
gap: ${({ theme }) => theme.spacing(3)};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
& .${Autocomplete_1.autocompleteClasses.inputRoot} .${InputBase_1.inputBaseClasses.input} {
|
|
60
|
+
min-width: ${constants_1.INPUT_MIN_WIDTH}px;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
& .${Autocomplete_1.autocompleteClasses.inputRoot} {
|
|
64
|
+
flex-wrap: nowrap;
|
|
65
|
+
}
|
|
66
|
+
|
|
53
67
|
`;
|
|
@@ -2,10 +2,11 @@ import { type AutocompleteInputChangeReason } from '@mui/material/Autocomplete';
|
|
|
2
2
|
import { type SyntheticEvent } from 'react';
|
|
3
3
|
import { type AutocompleteProps } from '../types';
|
|
4
4
|
type UseLogicParams<TAutocompleteValueProps, TMultiple extends boolean, TDisableClearable extends boolean, TFreeSolo extends boolean> = AutocompleteProps<TAutocompleteValueProps, TMultiple, TDisableClearable, TFreeSolo>;
|
|
5
|
-
export declare const useLogic: <TAutocompleteValueProps, TMultiple extends boolean, TDisableClearable extends boolean, TFreeSolo extends boolean>({ value, isOptionEqualToValue: externalOptionEqualToValue, autoHighlight, freeSolo, options, loading, isLoadedDataError, loadedDataError, noOptionsText, onInputChange, }: UseLogicParams<TAutocompleteValueProps, TMultiple, TDisableClearable, TFreeSolo>) => {
|
|
5
|
+
export declare const useLogic: <TAutocompleteValueProps, TMultiple extends boolean, TDisableClearable extends boolean, TFreeSolo extends boolean>({ value, isOptionEqualToValue: externalOptionEqualToValue, autoHighlight, freeSolo, options, multiple, className, loading, isLoadedDataError, loadedDataError, noOptionsText, onInputChange, }: UseLogicParams<TAutocompleteValueProps, TMultiple, TDisableClearable, TFreeSolo>) => {
|
|
6
6
|
isValueEmpty: boolean;
|
|
7
7
|
isPopperVisible: boolean | undefined;
|
|
8
8
|
autocompleteProps: {
|
|
9
|
+
className: string;
|
|
9
10
|
isOptionEqualToValue: (option: TAutocompleteValueProps, currentValue: TAutocompleteValueProps) => boolean;
|
|
10
11
|
autoHighlight: boolean;
|
|
11
12
|
noOptionsText: string | number | bigint | boolean | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<import("react").ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<import("react").ReactNode> | null | undefined> | null;
|
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.useLogic = void 0;
|
|
4
4
|
const react_1 = require("react");
|
|
5
|
+
const classNames_1 = require("../../utils/classNames");
|
|
6
|
+
const constants_1 = require("../constants");
|
|
5
7
|
const utils_1 = require("./utils");
|
|
6
|
-
const useLogic = ({ value, isOptionEqualToValue: externalOptionEqualToValue, autoHighlight = true, freeSolo, options, loading, isLoadedDataError, loadedDataError = 'Ошибка загрузки данных', noOptionsText = 'Нет данных', onInputChange, }) => {
|
|
8
|
+
const useLogic = ({ value, isOptionEqualToValue: externalOptionEqualToValue, autoHighlight = true, freeSolo, options, multiple, className, loading, isLoadedDataError, loadedDataError = 'Ошибка загрузки данных', noOptionsText = 'Нет данных', onInputChange, }) => {
|
|
7
9
|
const [innerInputValue, setInnerInputValue] = (0, react_1.useState)('');
|
|
8
10
|
const isValueEmpty = (0, utils_1.checkIsInputEmpty)(value);
|
|
9
11
|
const isInnerInputValueNotEmpty = innerInputValue.length >= 1;
|
|
@@ -24,10 +26,17 @@ const useLogic = ({ value, isOptionEqualToValue: externalOptionEqualToValue, aut
|
|
|
24
26
|
setInnerInputValue(currentValue);
|
|
25
27
|
}
|
|
26
28
|
};
|
|
29
|
+
const classnames = (0, react_1.useMemo)(() => {
|
|
30
|
+
return (0, classNames_1.classNames)(className, constants_1.autocompleteClassnames.root, {
|
|
31
|
+
[constants_1.autocompleteClassnames.multiple]: multiple,
|
|
32
|
+
[constants_1.autocompleteClassnames.emptyValue]: isValueEmpty,
|
|
33
|
+
});
|
|
34
|
+
}, [multiple, isValueEmpty]);
|
|
27
35
|
return {
|
|
28
36
|
isValueEmpty,
|
|
29
37
|
isPopperVisible,
|
|
30
38
|
autocompleteProps: {
|
|
39
|
+
className: classnames,
|
|
31
40
|
isOptionEqualToValue,
|
|
32
41
|
autoHighlight: freeSolo ? false : autoHighlight,
|
|
33
42
|
noOptionsText: isLoadedDataError ? loadedDataError : noOptionsText,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const MAX_TAG_WIDTH = "246px";
|
|
@@ -6,6 +6,8 @@ const Tag_1 = require("../../Tag");
|
|
|
6
6
|
exports.StyledTag = (0, styled_1.styled)(Tag_1.Tag, {
|
|
7
7
|
shouldForwardProp: (prop) => prop !== '$shrinks',
|
|
8
8
|
}) `
|
|
9
|
+
overflow: hidden;
|
|
10
|
+
|
|
9
11
|
/* 4em ширина необходима для отображения двух букв и избежания перекрытия кнопкой сброса всего текста тега */
|
|
10
12
|
min-width: ${({ $shrinks }) => ($shrinks ? 'calc(2em + 20px)' : 'unset')};
|
|
11
13
|
max-width: 246px;
|
|
@@ -11,11 +11,11 @@ const utils_1 = require("./utils");
|
|
|
11
11
|
* Не предназначен для использования в продуктах, не экспортируется из пакета
|
|
12
12
|
*/
|
|
13
13
|
const TagsList = (props) => {
|
|
14
|
-
const {
|
|
15
|
-
const { className,
|
|
16
|
-
return ((0, jsx_runtime_1.jsxs)(styles_1.Wrapper, { className: className, ref: tagsContainerRef, children: [visibleOptions?.map((option
|
|
17
|
-
const tagProps = getTagProps(option
|
|
18
|
-
return ((0, jsx_runtime_1.jsx)(Tag_1.Tag, { isDisabled: isDisabled, onClick: onClick, ...tagProps }, (0, utils_1.getKey)(option, keyId)));
|
|
19
|
-
}),
|
|
14
|
+
const { hiddenCount, tagsContainerRef, visibleOptions, getTagProps, showCounter, } = (0, useLogic_1.useLogic)(props);
|
|
15
|
+
const { className, keyId, isDisabled, onClick, getOptionLabel } = props;
|
|
16
|
+
return ((0, jsx_runtime_1.jsxs)(styles_1.Wrapper, { className: className, ref: tagsContainerRef, children: [visibleOptions?.map((option) => {
|
|
17
|
+
const tagProps = getTagProps(option);
|
|
18
|
+
return ((0, jsx_runtime_1.jsx)(Tag_1.Tag, { isDisabled: isDisabled, onClick: onClick, ...tagProps }, (0, utils_1.getKey)(option, keyId, getOptionLabel)));
|
|
19
|
+
}), showCounter && ((0, jsx_runtime_1.jsx)(styles_1.CounterTag, { isDisabled: isDisabled, label: `+${hiddenCount}`, onClick: onClick }, "more"))] }));
|
|
20
20
|
};
|
|
21
21
|
exports.TagsList = TagsList;
|
|
@@ -3,12 +3,16 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.CounterTag = exports.Wrapper = void 0;
|
|
4
4
|
const styled_1 = require("../styled");
|
|
5
5
|
const Tag_1 = require("../Tag");
|
|
6
|
+
const constants_1 = require("./constants");
|
|
6
7
|
const Tag_2 = require("./Tag");
|
|
7
8
|
exports.Wrapper = styled_1.styled.div `
|
|
9
|
+
overflow: hidden;
|
|
8
10
|
display: flex;
|
|
9
|
-
column-gap: ${
|
|
11
|
+
column-gap: ${constants_1.GAP_BETWEEN_TAGS}px;
|
|
10
12
|
`;
|
|
11
13
|
exports.CounterTag = (0, styled_1.styled)(Tag_2.Tag) `
|
|
14
|
+
overflow: unset;
|
|
15
|
+
|
|
12
16
|
.${Tag_1.tagClassnames.label} {
|
|
13
17
|
min-width: unset;
|
|
14
18
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type MouseEvent } from 'react';
|
|
1
|
+
import { type MouseEvent, type RefObject } from 'react';
|
|
2
2
|
export type TagValue = string | Record<string, unknown>;
|
|
3
3
|
export type TagsListProps<TData extends TagValue = TagValue> = {
|
|
4
4
|
/**
|
|
@@ -14,16 +14,25 @@ export type TagsListProps<TData extends TagValue = TagValue> = {
|
|
|
14
14
|
*/
|
|
15
15
|
isDisabled?: boolean;
|
|
16
16
|
/**
|
|
17
|
-
* Поле, используемое в качестве ключа
|
|
17
|
+
* Поле, используемое в качестве ключа списка.
|
|
18
|
+
* Если не передано, для генерации ключа будет использоваться getOptionLabel
|
|
18
19
|
*/
|
|
19
|
-
keyId
|
|
20
|
+
keyId?: TData extends string ? never : keyof TData;
|
|
20
21
|
/**
|
|
21
22
|
* Используется для определения строкового значения опции
|
|
22
23
|
*/
|
|
23
24
|
getOptionLabel: (value: TData) => string | number;
|
|
24
25
|
onChange: (value: TData[] | undefined) => void;
|
|
25
26
|
/**
|
|
26
|
-
* Функция, вызываемая при клике
|
|
27
|
+
* Функция, вызываемая при клике на тэг
|
|
27
28
|
*/
|
|
28
|
-
onClick
|
|
29
|
+
onClick?: (value: MouseEvent<HTMLDivElement>) => void;
|
|
30
|
+
/**
|
|
31
|
+
* Ref на внешний контейнер, чья ширина используется как база для расчёта доступного пространства..
|
|
32
|
+
*/
|
|
33
|
+
inputContainerRef?: RefObject<HTMLElement | null>;
|
|
34
|
+
/**
|
|
35
|
+
* Зарезервированная ширина, которая будет вычтена из доступной ширины при расчете количества отображаемых тегов
|
|
36
|
+
*/
|
|
37
|
+
reservedWidth?: number;
|
|
29
38
|
};
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
|
-
import type { TagValue } from '../types';
|
|
3
|
-
import { type TagsListProps } from '../types';
|
|
2
|
+
import type { TagsListProps, TagValue } from '../types';
|
|
4
3
|
type UseLogicParams<TData extends TagValue> = TagsListProps<TData>;
|
|
5
|
-
export declare const useLogic: <TData extends TagValue>({ data, keyId, getOptionLabel, onChange, }: UseLogicParams<TData>) => {
|
|
6
|
-
maxItems: number;
|
|
4
|
+
export declare const useLogic: <TData extends TagValue>({ data, keyId, getOptionLabel, onChange, inputContainerRef, reservedWidth, }: UseLogicParams<TData>) => {
|
|
7
5
|
visibleOptions: TData[];
|
|
6
|
+
hiddenCount: number;
|
|
7
|
+
showCounter: boolean;
|
|
8
8
|
tagsContainerRef: import("react").RefObject<HTMLDivElement | null>;
|
|
9
|
-
getTagProps: (option: TData
|
|
9
|
+
getTagProps: (option: TData) => {
|
|
10
10
|
label: string | number;
|
|
11
11
|
shrinks: boolean;
|
|
12
12
|
onDelete: () => void;
|