@astral/ui 4.106.0 → 4.107.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.js +2 -3
- package/components/Onboarding/ui/StepStrategy/steps/HighlightStep/styles.d.ts +1 -1
- package/components/Select/Select.js +4 -3
- package/components/Select/useLogic/useLogic.d.ts +11 -2
- package/components/Select/useLogic/useLogic.js +4 -1
- package/components/TagsList/PopoverTags/PopoverTags.d.ts +7 -0
- package/components/TagsList/PopoverTags/PopoverTags.js +8 -0
- package/components/TagsList/PopoverTags/index.d.ts +2 -0
- package/components/TagsList/PopoverTags/index.js +2 -0
- package/components/TagsList/PopoverTags/styles.d.ts +8 -0
- package/components/TagsList/PopoverTags/styles.js +15 -0
- package/components/TagsList/PopoverTags/types.d.ts +24 -0
- package/components/TagsList/PopoverTags/types.js +1 -0
- package/components/TagsList/Tag/Tag.d.ts +9 -1
- package/components/TagsList/Tag/Tag.js +4 -3
- package/components/TagsList/TagsList.js +11 -5
- package/components/TagsList/constants.d.ts +35 -0
- package/components/TagsList/constants.js +35 -0
- package/components/TagsList/styles.d.ts +9 -1
- package/components/TagsList/styles.js +20 -1
- package/components/TagsList/types.d.ts +4 -0
- package/components/TagsList/useLogic/hooks/index.d.ts +1 -0
- package/components/TagsList/useLogic/hooks/index.js +1 -0
- package/components/TagsList/useLogic/hooks/useHoverDelay/index.d.ts +1 -0
- package/components/TagsList/useLogic/hooks/useHoverDelay/index.js +1 -0
- package/components/TagsList/useLogic/hooks/useHoverDelay/types.d.ts +20 -0
- package/components/TagsList/useLogic/hooks/useHoverDelay/types.js +1 -0
- package/components/TagsList/useLogic/hooks/useHoverDelay/useHoverDelay.d.ts +5 -0
- package/components/TagsList/useLogic/hooks/useHoverDelay/useHoverDelay.js +27 -0
- package/components/TagsList/useLogic/useLogic.d.ts +14 -2
- package/components/TagsList/useLogic/useLogic.js +84 -4
- package/components/TagsList/utils/calculatePopoverWidth/calculatePopoverWidth.d.ts +5 -0
- package/components/TagsList/utils/calculatePopoverWidth/calculatePopoverWidth.js +22 -0
- package/components/TagsList/utils/calculatePopoverWidth/index.d.ts +1 -0
- package/components/TagsList/utils/calculatePopoverWidth/index.js +1 -0
- package/components/TagsList/utils/index.d.ts +1 -0
- package/components/TagsList/utils/index.js +1 -0
- package/components/TreeLikeAsyncAutocomplete/Input/Input.js +3 -2
- package/components/TreeLikeAsyncAutocomplete/Input/useLogic/useLogic.d.ts +3 -2
- package/components/TreeLikeAsyncAutocomplete/Input/useLogic/useLogic.js +3 -1
- package/components/TreeLikeAutocomplete/Input/Input.js +2 -2
- package/components/TreeLikeAutocomplete/Input/useLogic/useLogic.d.ts +2 -1
- package/components/TreeLikeAutocomplete/Input/useLogic/useLogic.js +3 -1
- package/node/components/Autocomplete/Autocomplete.js +2 -3
- package/node/components/Onboarding/ui/StepStrategy/steps/HighlightStep/styles.d.ts +1 -1
- package/node/components/Select/Select.js +4 -3
- package/node/components/Select/useLogic/useLogic.d.ts +11 -2
- package/node/components/Select/useLogic/useLogic.js +4 -1
- package/node/components/TagsList/PopoverTags/PopoverTags.d.ts +7 -0
- package/node/components/TagsList/PopoverTags/PopoverTags.js +12 -0
- package/node/components/TagsList/PopoverTags/index.d.ts +2 -0
- package/node/components/TagsList/PopoverTags/index.js +18 -0
- package/node/components/TagsList/PopoverTags/styles.d.ts +8 -0
- package/node/components/TagsList/PopoverTags/styles.js +18 -0
- package/node/components/TagsList/PopoverTags/types.d.ts +24 -0
- package/node/components/TagsList/PopoverTags/types.js +2 -0
- package/node/components/TagsList/Tag/Tag.d.ts +9 -1
- package/node/components/TagsList/Tag/Tag.js +4 -4
- package/node/components/TagsList/TagsList.js +10 -4
- package/node/components/TagsList/constants.d.ts +35 -0
- package/node/components/TagsList/constants.js +36 -1
- package/node/components/TagsList/styles.d.ts +9 -1
- package/node/components/TagsList/styles.js +20 -1
- package/node/components/TagsList/types.d.ts +4 -0
- package/node/components/TagsList/useLogic/hooks/index.d.ts +1 -0
- package/node/components/TagsList/useLogic/hooks/index.js +17 -0
- package/node/components/TagsList/useLogic/hooks/useHoverDelay/index.d.ts +1 -0
- package/node/components/TagsList/useLogic/hooks/useHoverDelay/index.js +17 -0
- package/node/components/TagsList/useLogic/hooks/useHoverDelay/types.d.ts +20 -0
- package/node/components/TagsList/useLogic/hooks/useHoverDelay/types.js +2 -0
- package/node/components/TagsList/useLogic/hooks/useHoverDelay/useHoverDelay.d.ts +5 -0
- package/node/components/TagsList/useLogic/hooks/useHoverDelay/useHoverDelay.js +31 -0
- package/node/components/TagsList/useLogic/useLogic.d.ts +14 -2
- package/node/components/TagsList/useLogic/useLogic.js +81 -1
- package/node/components/TagsList/utils/calculatePopoverWidth/calculatePopoverWidth.d.ts +5 -0
- package/node/components/TagsList/utils/calculatePopoverWidth/calculatePopoverWidth.js +26 -0
- package/node/components/TagsList/utils/calculatePopoverWidth/index.d.ts +1 -0
- package/node/components/TagsList/utils/calculatePopoverWidth/index.js +17 -0
- package/node/components/TagsList/utils/index.d.ts +1 -0
- package/node/components/TagsList/utils/index.js +3 -1
- package/node/components/TreeLikeAsyncAutocomplete/Input/Input.js +3 -2
- package/node/components/TreeLikeAsyncAutocomplete/Input/useLogic/useLogic.d.ts +3 -2
- package/node/components/TreeLikeAsyncAutocomplete/Input/useLogic/useLogic.js +3 -1
- package/node/components/TreeLikeAutocomplete/Input/Input.js +2 -2
- package/node/components/TreeLikeAutocomplete/Input/useLogic/useLogic.d.ts +2 -1
- package/node/components/TreeLikeAutocomplete/Input/useLogic/useLogic.js +3 -1
- package/package.json +1 -1
|
@@ -23,8 +23,8 @@ const AutocompleteInner = (props, ref) => {
|
|
|
23
23
|
if (!multiple || !Array.isArray(value)) {
|
|
24
24
|
return null;
|
|
25
25
|
}
|
|
26
|
-
|
|
27
|
-
option.toString(), inputContainerRef: inputBaseRef, reservedWidth: INPUT_MIN_WIDTH, onChange: (tagValues) => {
|
|
26
|
+
return (_jsx(TagsList, { data: value, getOptionLabel: (option) => getOptionLabel?.(option) ??
|
|
27
|
+
option.toString(), inputContainerRef: inputBaseRef, fieldRef: inputBaseRef, reservedWidth: INPUT_MIN_WIDTH, onChange: (tagValues) => {
|
|
28
28
|
if (!onChange) {
|
|
29
29
|
return;
|
|
30
30
|
}
|
|
@@ -36,7 +36,6 @@ const AutocompleteInner = (props, ref) => {
|
|
|
36
36
|
const reason = 'removeOption';
|
|
37
37
|
onChange(syntheticEvent, tagValues, reason);
|
|
38
38
|
} }));
|
|
39
|
-
return tagsListElement;
|
|
40
39
|
};
|
|
41
40
|
const generalInputParams = {
|
|
42
41
|
...inputParams,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
|
-
export declare const StepPopover: import("../../../../../styled").StyledComponent<Omit<import("../../../../../NewPopover").NewPopoverProps, "title" | "
|
|
2
|
+
export declare const StepPopover: import("../../../../../styled").StyledComponent<Omit<import("../../../../../NewPopover").NewPopoverProps, "title" | "hasArrow" | "disableMobileDrawer"> & {
|
|
3
3
|
variant?: import("../../../../../HintPopover").HintPopoverVariant | undefined;
|
|
4
4
|
title?: import("react").ReactNode;
|
|
5
5
|
action?: import("react").ReactNode;
|
|
@@ -18,7 +18,7 @@ import { EndAdornmentWrapper, Placeholder, StateWrapper, StyledSelect, } from '.
|
|
|
18
18
|
import { useLogic } from './useLogic';
|
|
19
19
|
const ClearButton = forwardRef(({ onClick, disabled }, ref) => (_jsx(IconButton, { disabled: disabled, ref: ref, onClick: onClick, variant: "text", title: CLEAR_TEXT, "aria-label": CLEAR_TEXT, children: _jsx(CrossOutlineMd, {}) })));
|
|
20
20
|
const SelectInner = ({ required, getOptionLabel, placeholder, helperText, hideHelperText = false, loading, success, children, disabled, error, label, fullWidth, onChange: externalOnChange, isShowClearButton, isEnableAllSelection = false, valueOptions, value, onSelectAll, onUnselectAll, ...props }, ref) => {
|
|
21
|
-
const { isOpened, isShowingClearButton, isNoData, onClearAll, openSelect, closeSelect, resetButtonRef, isShowingSelectAll, handleChangeOption, isSelectedAll, isIndeterminate, handleChangeArrayValue, selectAllClassName, findMenuItemsLabel, isShowingPlaceholder, } = useLogic({
|
|
21
|
+
const { isOpened, isShowingClearButton, isNoData, onClearAll, openSelect, closeSelect, resetButtonRef, isShowingSelectAll, handleChangeOption, isSelectedAll, isIndeterminate, handleChangeArrayValue, selectAllClassName, findMenuItemsLabel, isShowingPlaceholder, fieldRef, } = useLogic({
|
|
22
22
|
...props,
|
|
23
23
|
children,
|
|
24
24
|
value,
|
|
@@ -30,11 +30,12 @@ const SelectInner = ({ required, getOptionLabel, placeholder, helperText, hideHe
|
|
|
30
30
|
onSelectAll,
|
|
31
31
|
onUnselectAll,
|
|
32
32
|
loading,
|
|
33
|
+
ref,
|
|
33
34
|
});
|
|
34
35
|
const renderValue = (selectedOptions) => {
|
|
35
36
|
// Массив с выбранными опциями
|
|
36
37
|
if (Array.isArray(selectedOptions) && selectedOptions.length) {
|
|
37
|
-
return (_jsx(TagsList, { data: selectedOptions, getOptionLabel: getOptionLabel || ((optionLabel) => optionLabel), onChange: handleChangeArrayValue, onClick: openSelect }));
|
|
38
|
+
return (_jsx(TagsList, { data: selectedOptions, getOptionLabel: getOptionLabel || ((optionLabel) => optionLabel), fieldRef: fieldRef, onChange: handleChangeArrayValue, onClick: openSelect }));
|
|
38
39
|
}
|
|
39
40
|
// Пустой массив или пустая строка
|
|
40
41
|
if ((Array.isArray(selectedOptions) || typeof selectedOptions === 'string') &&
|
|
@@ -47,6 +48,6 @@ const SelectInner = ({ required, getOptionLabel, placeholder, helperText, hideHe
|
|
|
47
48
|
}
|
|
48
49
|
return findMenuItemsLabel(children, selectedOptions);
|
|
49
50
|
};
|
|
50
|
-
return (_jsxs(FormControl, { error: error, fullWidth: fullWidth, children: [label && (_jsx(InputLabel, { htmlFor: "grouped-select", required: required, disabled: disabled, children: label })), _jsxs(StyledSelect, { ...props, value: value === null || value === undefined ? '' : value, open: isOpened, disabled: disabled, onOpen: openSelect, onClose: closeSelect, renderValue: renderValue, IconComponent: () => null, displayEmpty: true, ref:
|
|
51
|
+
return (_jsxs(FormControl, { error: error, fullWidth: fullWidth, children: [label && (_jsx(InputLabel, { htmlFor: "grouped-select", required: required, disabled: disabled, children: label })), _jsxs(StyledSelect, { ...props, value: value === null || value === undefined ? '' : value, open: isOpened, disabled: disabled, onOpen: openSelect, onClose: closeSelect, renderValue: renderValue, IconComponent: () => null, displayEmpty: true, ref: fieldRef, fullWidth: fullWidth, onChange: handleChangeOption, "$isShowingPlaceholder": isShowingPlaceholder, endAdornment: _jsxs(EndAdornmentWrapper, { children: [loading && _jsx(Loader, { color: "primary", size: "small" }), !loading && isShowingClearButton && (_jsx(ClearButton, { disabled: disabled, ref: resetButtonRef, onClick: onClearAll })), !loading && (_jsx(IconButton, { variant: "text", disabled: disabled, onClick: openSelect, children: !isOpened ? _jsx(DownOutlineMd, {}) : _jsx(UpOutlineMd, {}) }))] }), children: [_jsx(Placeholder, { value: "", children: placeholder }), !loading && isShowingSelectAll && (_jsxs(MenuItem, { className: selectAllClassName, selected: isSelectedAll, value: SELECT_ALL_VALUE, children: [_jsx(ListItemIcon, { children: _jsx(Checkbox, { checked: isSelectedAll, indeterminate: isIndeterminate }) }), "\u0412\u044B\u0431\u0440\u0430\u0442\u044C \u0432\u0441\u0435"] })), !loading && children, !loading && isNoData && _jsx(StateWrapper, { children: "\u041D\u0435\u0442 \u0434\u0430\u043D\u043D\u044B\u0445" })] }), _jsx(FormHelperText, { error: error, success: success, hideHelperText: hideHelperText, children: helperText })] }));
|
|
51
52
|
};
|
|
52
53
|
export const Select = forwardRefWithGeneric(SelectInner);
|
|
@@ -1,6 +1,13 @@
|
|
|
1
|
-
import { type ReactNode, type SyntheticEvent } from 'react';
|
|
1
|
+
import { type ForwardedRef, type ReactNode, type SyntheticEvent } from 'react';
|
|
2
2
|
import { type SelectProps } from '../types';
|
|
3
|
-
|
|
3
|
+
type UseLogicParams<TValue> = Omit<SelectProps<TValue>, 'ref'> & {
|
|
4
|
+
/**
|
|
5
|
+
* Ref, пробрасываемый на контейнер поля: по нему считается ширина
|
|
6
|
+
* всплывающего окна тэгов и он служит якорем его позиционирования
|
|
7
|
+
*/
|
|
8
|
+
ref: ForwardedRef<HTMLDivElement>;
|
|
9
|
+
};
|
|
10
|
+
export declare const useLogic: <TValue>({ value, onChange, children, open: externalIsOpened, defaultOpen, multiple, isEnableAllSelection, isShowClearButton, valueOptions, onSelectAll, onUnselectAll, name, placeholder, onClose, onOpen, loading, ref, }: UseLogicParams<TValue>) => {
|
|
4
11
|
isOpened: boolean;
|
|
5
12
|
isNoData: boolean;
|
|
6
13
|
isShowingClearButton: boolean;
|
|
@@ -17,4 +24,6 @@ export declare const useLogic: <TValue>({ value, onChange, children, open: exter
|
|
|
17
24
|
selectAllClassName: string | undefined;
|
|
18
25
|
findMenuItemsLabel: (nodes: ReactNode, selectedValue: TValue) => ReactNode;
|
|
19
26
|
isShowingPlaceholder: boolean;
|
|
27
|
+
fieldRef: import("react").RefObject<HTMLDivElement | null>;
|
|
20
28
|
};
|
|
29
|
+
export {};
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { menuItemClasses } from '@mui/material/MenuItem';
|
|
2
2
|
import { Children, isValidElement, useRef, useState, } from 'react';
|
|
3
3
|
import { MenuItem } from '../../MenuItem';
|
|
4
|
+
import { useForwardedRef } from '../../useForwardedRef';
|
|
4
5
|
import { getNodeText } from '../../utils/getNodeText';
|
|
5
6
|
import { isSyncReactElement } from '../../utils/isSyncReactElement';
|
|
6
7
|
import { SELECT_ALL_VALUE } from '../constants';
|
|
7
8
|
import { isShowingPlaceholder } from './utils/isShowingPlaceholder';
|
|
8
|
-
export const useLogic = ({ value, onChange, children, open: externalIsOpened, defaultOpen, multiple, isEnableAllSelection, isShowClearButton = true, valueOptions, onSelectAll, onUnselectAll, name, placeholder, onClose, onOpen, loading, }) => {
|
|
9
|
+
export const useLogic = ({ value, onChange, children, open: externalIsOpened, defaultOpen, multiple, isEnableAllSelection, isShowClearButton = true, valueOptions, onSelectAll, onUnselectAll, name, placeholder, onClose, onOpen, loading, ref, }) => {
|
|
9
10
|
const [isOpened, setOpened] = useState(!loading && (defaultOpen || externalIsOpened || false));
|
|
11
|
+
const fieldRef = useForwardedRef(ref);
|
|
10
12
|
const resetButtonRef = useRef(null);
|
|
11
13
|
const optionsLength = Array.isArray(valueOptions)
|
|
12
14
|
? valueOptions?.length
|
|
@@ -129,5 +131,6 @@ export const useLogic = ({ value, onChange, children, open: externalIsOpened, de
|
|
|
129
131
|
selectAllClassName,
|
|
130
132
|
findMenuItemsLabel,
|
|
131
133
|
isShowingPlaceholder: isShowingPlaceholder(value, placeholder),
|
|
134
|
+
fieldRef,
|
|
132
135
|
};
|
|
133
136
|
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { TagValue } from '../types';
|
|
2
|
+
import { type PopoverTagsProps } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Показывает все выбранные элементы тэгами с переносом по строкам.
|
|
5
|
+
* Используется как содержимое всплывающего окна TagsList
|
|
6
|
+
*/
|
|
7
|
+
export declare const PopoverTags: <TData extends TagValue>({ data, keyId, isDisabled, getOptionLabel, getTagProps, }: PopoverTagsProps<TData>) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { getKey } from '../utils';
|
|
3
|
+
import { StyledTag, Wrapper } from './styles';
|
|
4
|
+
/**
|
|
5
|
+
* Показывает все выбранные элементы тэгами с переносом по строкам.
|
|
6
|
+
* Используется как содержимое всплывающего окна TagsList
|
|
7
|
+
*/
|
|
8
|
+
export const PopoverTags = ({ data, keyId, isDisabled, getOptionLabel, getTagProps, }) => (_jsx(Wrapper, { children: data.map((option) => (_jsx(StyledTag, { isDisabled: isDisabled, ...getTagProps(option) }, getKey(option, keyId, getOptionLabel)))) }));
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
export declare const Wrapper: import("../../styled").StyledComponent<{
|
|
3
|
+
theme?: import("@emotion/react").Theme | undefined;
|
|
4
|
+
as?: import("react").ElementType<any, keyof import("react").JSX.IntrinsicElements> | undefined;
|
|
5
|
+
}, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {}>;
|
|
6
|
+
export declare const StyledTag: import("../../styled").StyledComponent<import("../Tag").TagProps & import("react").RefAttributes<HTMLDivElement> & {
|
|
7
|
+
theme?: import("@emotion/react").Theme | undefined;
|
|
8
|
+
}, {}, {}>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { styled } from '../../styled';
|
|
2
|
+
import { POPOVER_MAX_HEIGHT, POPOVER_TAGS_GAP_SPACING, POPOVER_TAGS_PADDING_SPACING, } from '../constants';
|
|
3
|
+
import { Tag } from '../Tag';
|
|
4
|
+
export const Wrapper = styled.div `
|
|
5
|
+
overflow-y: auto;
|
|
6
|
+
display: flex;
|
|
7
|
+
flex-wrap: wrap;
|
|
8
|
+
gap: ${({ theme }) => theme.spacing(POPOVER_TAGS_GAP_SPACING)};
|
|
9
|
+
|
|
10
|
+
max-height: ${POPOVER_MAX_HEIGHT}px;
|
|
11
|
+
padding-inline: ${({ theme }) => theme.spacing(POPOVER_TAGS_PADDING_SPACING)};
|
|
12
|
+
`;
|
|
13
|
+
export const StyledTag = styled(Tag) `
|
|
14
|
+
max-width: 100%;
|
|
15
|
+
`;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type TagProps } from '../Tag';
|
|
2
|
+
import { type TagValue } from '../types';
|
|
3
|
+
export type PopoverTagsProps<TData extends TagValue = TagValue> = {
|
|
4
|
+
/**
|
|
5
|
+
* Полный список выбранных элементов
|
|
6
|
+
*/
|
|
7
|
+
data: TData[];
|
|
8
|
+
/**
|
|
9
|
+
* Поле, используемое в качестве ключа списка
|
|
10
|
+
*/
|
|
11
|
+
keyId?: TData extends object ? keyof TData : never;
|
|
12
|
+
/**
|
|
13
|
+
* Если `true`, то тэги будут недоступны для взаимодействия
|
|
14
|
+
*/
|
|
15
|
+
isDisabled?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Используется для определения строкового значения опции
|
|
18
|
+
*/
|
|
19
|
+
getOptionLabel: (value: TData) => string | number;
|
|
20
|
+
/**
|
|
21
|
+
* Возвращает пропсы тэга, включая обработчик удаления
|
|
22
|
+
*/
|
|
23
|
+
getTagProps: (option: TData) => Pick<TagProps, 'label' | 'onDelete'>;
|
|
24
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -21,9 +21,17 @@ export type TagProps = {
|
|
|
21
21
|
* Хендлер клика по тегу
|
|
22
22
|
*/
|
|
23
23
|
onClick?: (value: MouseEvent<HTMLDivElement>) => void;
|
|
24
|
+
/**
|
|
25
|
+
* Хендлер наведения указателя на тег
|
|
26
|
+
*/
|
|
27
|
+
onMouseEnter?: (value: MouseEvent<HTMLDivElement>) => void;
|
|
28
|
+
/**
|
|
29
|
+
* Хендлер увода указателя с тега
|
|
30
|
+
*/
|
|
31
|
+
onMouseLeave?: (value: MouseEvent<HTMLDivElement>) => void;
|
|
24
32
|
/**
|
|
25
33
|
* Название класса, применяется к корневому компоненту
|
|
26
34
|
*/
|
|
27
35
|
className?: string;
|
|
28
36
|
};
|
|
29
|
-
export declare const Tag: (
|
|
37
|
+
export declare const Tag: import("react").ForwardRefExoticComponent<TagProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef } from 'react';
|
|
2
3
|
import { OverflowTypography } from '../../OverflowTypography';
|
|
3
4
|
import { StyledTag } from './styles';
|
|
4
5
|
import { useLogic } from './useLogic';
|
|
5
|
-
export const Tag = (props) => {
|
|
6
|
+
export const Tag = forwardRef((props, ref) => {
|
|
6
7
|
const { onMouseDown } = useLogic();
|
|
7
8
|
const { shrinks, isDisabled, label, ...restProps } = props;
|
|
8
|
-
return (_jsx(StyledTag, { "$shrinks": shrinks, color: "grey", variant: "light", disabled: isDisabled, label: _jsx(OverflowTypography, { children: label }), ...restProps, onMouseDown: onMouseDown }));
|
|
9
|
-
};
|
|
9
|
+
return (_jsx(StyledTag, { ref: ref, "$shrinks": shrinks, color: "grey", variant: "light", disabled: isDisabled, label: _jsx(OverflowTypography, { children: label }), ...restProps, onMouseDown: onMouseDown }));
|
|
10
|
+
});
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { CrossOutlineMd } from '../../icons/CrossOutlineMd';
|
|
3
|
+
import { IconButton } from '../IconButton';
|
|
4
|
+
import { NewPopover } from '../NewPopover';
|
|
5
|
+
import { Typography } from '../Typography';
|
|
6
|
+
import { POPOVER_CLOSE_TEXT, POPOVER_TITLE_TEXT } from './constants';
|
|
7
|
+
import { PopoverTags } from './PopoverTags';
|
|
8
|
+
import { CounterTag, PopoverContentWrapper, PopoverHeader, Wrapper, } from './styles';
|
|
3
9
|
import { Tag } from './Tag';
|
|
4
10
|
import { useLogic } from './useLogic';
|
|
5
11
|
import { getKey } from './utils';
|
|
@@ -8,10 +14,10 @@ import { getKey } from './utils';
|
|
|
8
14
|
* Не предназначен для использования в продуктах, не экспортируется из пакета
|
|
9
15
|
*/
|
|
10
16
|
export const TagsList = (props) => {
|
|
11
|
-
const { hiddenCount, tagsContainerRef, visibleOptions, getTagProps, showCounter, } = useLogic(props);
|
|
12
|
-
const { className, keyId, isDisabled,
|
|
17
|
+
const { hiddenCount, tagsContainerRef, counterRef, visibleOptions, getTagProps, showCounter, isPopoverOpen, isPopoverEnabled, setPopoverContentRef, popoverContentCssVars, stopPopoverEventPropagation, popoverAnchorEl, closePopover, startPopoverDelay, cancelPopoverDelay, handleTagClick, handleCounterClick, } = useLogic(props);
|
|
18
|
+
const { className, data = [], keyId, isDisabled, getOptionLabel } = props;
|
|
13
19
|
return (_jsxs(Wrapper, { className: className, ref: tagsContainerRef, children: [visibleOptions?.map((option) => {
|
|
14
20
|
const tagProps = getTagProps(option);
|
|
15
|
-
return (_jsx(Tag, { isDisabled: isDisabled, onClick:
|
|
16
|
-
}), showCounter && (_jsx(CounterTag, { isDisabled: isDisabled, label: `+${hiddenCount}`, onClick:
|
|
21
|
+
return (_jsx(Tag, { isDisabled: isDisabled, onClick: handleTagClick, ...tagProps }, getKey(option, keyId, getOptionLabel)));
|
|
22
|
+
}), showCounter && (_jsx(CounterTag, { ref: counterRef, isDisabled: isDisabled, label: `+${hiddenCount}`, onClick: handleCounterClick, onMouseEnter: isPopoverEnabled ? startPopoverDelay : undefined, onMouseLeave: isPopoverEnabled ? cancelPopoverDelay : undefined }, "more")), _jsx(NewPopover, { isOpen: isPopoverOpen, anchorEl: popoverAnchorEl, disableAutoFocus: true, onClose: closePopover, children: _jsxs(PopoverContentWrapper, { ref: setPopoverContentRef, style: popoverContentCssVars, onClick: stopPopoverEventPropagation, onMouseDown: stopPopoverEventPropagation, children: [_jsxs(PopoverHeader, { children: [_jsx(Typography, { variant: "h5", children: POPOVER_TITLE_TEXT }), _jsx(IconButton, { variant: "text", title: POPOVER_CLOSE_TEXT, "aria-label": POPOVER_CLOSE_TEXT, onClick: closePopover, children: _jsx(CrossOutlineMd, {}) })] }), _jsx(PopoverTags, { data: data, keyId: keyId, isDisabled: isDisabled, getOptionLabel: getOptionLabel, getTagProps: getTagProps })] }) })] }));
|
|
17
23
|
};
|
|
@@ -1,2 +1,37 @@
|
|
|
1
1
|
export declare const MIN_AVAILABLE_WIDTH = 50;
|
|
2
2
|
export declare const GAP_BETWEEN_TAGS = 4;
|
|
3
|
+
/**
|
|
4
|
+
* Задержка появления всплывающего окна при наведении на счётчик (мс)
|
|
5
|
+
*/
|
|
6
|
+
export declare const POPOVER_HOVER_DELAY = 500;
|
|
7
|
+
/**
|
|
8
|
+
* Максимальная ширина всплывающего окна (px)
|
|
9
|
+
*/
|
|
10
|
+
export declare const POPOVER_MAX_WIDTH = 480;
|
|
11
|
+
/**
|
|
12
|
+
* Максимальная высота всплывающего окна (px)
|
|
13
|
+
*/
|
|
14
|
+
export declare const POPOVER_MAX_HEIGHT = 370;
|
|
15
|
+
/**
|
|
16
|
+
* Количество тэгов, которые всплывающее окно вмещает в строку в любом случае:
|
|
17
|
+
* задаёт его минимальную ширину
|
|
18
|
+
*/
|
|
19
|
+
export declare const POPOVER_MIN_TAGS_IN_ROW = 2;
|
|
20
|
+
/**
|
|
21
|
+
* Отступ между тэгами во всплывающем окне в единицах theme.spacing.
|
|
22
|
+
* Используется и в стилях, и в расчёте минимальной ширины окна
|
|
23
|
+
*/
|
|
24
|
+
export declare const POPOVER_TAGS_GAP_SPACING = 2;
|
|
25
|
+
/**
|
|
26
|
+
* Горизонтальный отступ контейнера тэгов во всплывающем окне в единицах
|
|
27
|
+
* theme.spacing. Используется и в стилях, и в расчёте минимальной ширины окна
|
|
28
|
+
*/
|
|
29
|
+
export declare const POPOVER_TAGS_PADDING_SPACING = 4;
|
|
30
|
+
/**
|
|
31
|
+
* Заголовок всплывающего окна со списком выбранных элементов
|
|
32
|
+
*/
|
|
33
|
+
export declare const POPOVER_TITLE_TEXT = "\u0412\u044B\u0431\u0440\u0430\u043D\u043D\u044B\u0435 \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u044B";
|
|
34
|
+
/**
|
|
35
|
+
* Доступное имя кнопки, закрывающей всплывающее окно
|
|
36
|
+
*/
|
|
37
|
+
export declare const POPOVER_CLOSE_TEXT = "\u0417\u0430\u043A\u0440\u044B\u0442\u044C";
|
|
@@ -1,2 +1,37 @@
|
|
|
1
1
|
export const MIN_AVAILABLE_WIDTH = 50;
|
|
2
2
|
export const GAP_BETWEEN_TAGS = 4; // 4px
|
|
3
|
+
/**
|
|
4
|
+
* Задержка появления всплывающего окна при наведении на счётчик (мс)
|
|
5
|
+
*/
|
|
6
|
+
export const POPOVER_HOVER_DELAY = 500;
|
|
7
|
+
/**
|
|
8
|
+
* Максимальная ширина всплывающего окна (px)
|
|
9
|
+
*/
|
|
10
|
+
export const POPOVER_MAX_WIDTH = 480;
|
|
11
|
+
/**
|
|
12
|
+
* Максимальная высота всплывающего окна (px)
|
|
13
|
+
*/
|
|
14
|
+
export const POPOVER_MAX_HEIGHT = 370;
|
|
15
|
+
/**
|
|
16
|
+
* Количество тэгов, которые всплывающее окно вмещает в строку в любом случае:
|
|
17
|
+
* задаёт его минимальную ширину
|
|
18
|
+
*/
|
|
19
|
+
export const POPOVER_MIN_TAGS_IN_ROW = 2;
|
|
20
|
+
/**
|
|
21
|
+
* Отступ между тэгами во всплывающем окне в единицах theme.spacing.
|
|
22
|
+
* Используется и в стилях, и в расчёте минимальной ширины окна
|
|
23
|
+
*/
|
|
24
|
+
export const POPOVER_TAGS_GAP_SPACING = 2;
|
|
25
|
+
/**
|
|
26
|
+
* Горизонтальный отступ контейнера тэгов во всплывающем окне в единицах
|
|
27
|
+
* theme.spacing. Используется и в стилях, и в расчёте минимальной ширины окна
|
|
28
|
+
*/
|
|
29
|
+
export const POPOVER_TAGS_PADDING_SPACING = 4;
|
|
30
|
+
/**
|
|
31
|
+
* Заголовок всплывающего окна со списком выбранных элементов
|
|
32
|
+
*/
|
|
33
|
+
export const POPOVER_TITLE_TEXT = 'Выбранные элементы';
|
|
34
|
+
/**
|
|
35
|
+
* Доступное имя кнопки, закрывающей всплывающее окно
|
|
36
|
+
*/
|
|
37
|
+
export const POPOVER_CLOSE_TEXT = 'Закрыть';
|
|
@@ -3,6 +3,14 @@ export declare const Wrapper: import("../styled").StyledComponent<{
|
|
|
3
3
|
theme?: import("@emotion/react").Theme | undefined;
|
|
4
4
|
as?: import("react").ElementType<any, keyof import("react").JSX.IntrinsicElements> | undefined;
|
|
5
5
|
}, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {}>;
|
|
6
|
-
export declare const CounterTag: import("../styled").StyledComponent<import("./Tag").TagProps & {
|
|
6
|
+
export declare const CounterTag: import("../styled").StyledComponent<import("./Tag").TagProps & import("react").RefAttributes<HTMLDivElement> & {
|
|
7
7
|
theme?: import("@emotion/react").Theme | undefined;
|
|
8
8
|
}, {}, {}>;
|
|
9
|
+
export declare const PopoverContentWrapper: import("../styled").StyledComponent<{
|
|
10
|
+
theme?: import("@emotion/react").Theme | undefined;
|
|
11
|
+
as?: import("react").ElementType<any, keyof import("react").JSX.IntrinsicElements> | undefined;
|
|
12
|
+
}, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {}>;
|
|
13
|
+
export declare const PopoverHeader: import("../styled").StyledComponent<{
|
|
14
|
+
theme?: import("@emotion/react").Theme | undefined;
|
|
15
|
+
as?: import("react").ElementType<any, keyof import("react").JSX.IntrinsicElements> | undefined;
|
|
16
|
+
}, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {}>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { styled } from '../styled';
|
|
2
2
|
import { tagClassnames } from '../Tag';
|
|
3
|
-
import { GAP_BETWEEN_TAGS } from './constants';
|
|
3
|
+
import { GAP_BETWEEN_TAGS, POPOVER_MAX_WIDTH } from './constants';
|
|
4
4
|
import { Tag } from './Tag';
|
|
5
5
|
export const Wrapper = styled.div `
|
|
6
6
|
overflow: hidden;
|
|
@@ -8,9 +8,28 @@ export const Wrapper = styled.div `
|
|
|
8
8
|
column-gap: ${GAP_BETWEEN_TAGS}px;
|
|
9
9
|
`;
|
|
10
10
|
export const CounterTag = styled(Tag) `
|
|
11
|
+
cursor: pointer;
|
|
12
|
+
|
|
11
13
|
overflow: unset;
|
|
12
14
|
|
|
13
15
|
.${tagClassnames.label} {
|
|
14
16
|
min-width: unset;
|
|
15
17
|
}
|
|
16
18
|
`;
|
|
19
|
+
export const PopoverContentWrapper = styled.div `
|
|
20
|
+
--tags-list-popover-width: ${POPOVER_MAX_WIDTH}px;
|
|
21
|
+
display: flex;
|
|
22
|
+
flex-direction: column;
|
|
23
|
+
gap: ${({ theme }) => theme.spacing(2)};
|
|
24
|
+
|
|
25
|
+
width: var(--tags-list-popover-width);
|
|
26
|
+
max-width: ${POPOVER_MAX_WIDTH}px;
|
|
27
|
+
padding-block: ${({ theme }) => theme.spacing(4)};
|
|
28
|
+
`;
|
|
29
|
+
export const PopoverHeader = styled.div `
|
|
30
|
+
display: flex;
|
|
31
|
+
align-items: center;
|
|
32
|
+
justify-content: space-between;
|
|
33
|
+
|
|
34
|
+
padding-inline: ${({ theme }) => theme.spacing(4)};
|
|
35
|
+
`;
|
|
@@ -31,6 +31,10 @@ export type TagsListProps<TData extends TagValue = TagValue> = {
|
|
|
31
31
|
* Ref на внешний контейнер, чья ширина используется как база для расчёта доступного пространства..
|
|
32
32
|
*/
|
|
33
33
|
inputContainerRef?: RefObject<HTMLElement | null>;
|
|
34
|
+
/**
|
|
35
|
+
* Ref на поле инпута
|
|
36
|
+
*/
|
|
37
|
+
fieldRef: RefObject<HTMLElement | null>;
|
|
34
38
|
/**
|
|
35
39
|
* Зарезервированная ширина, которая будет вычтена из доступной ширины при расчете количества отображаемых тегов
|
|
36
40
|
*/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './useHoverDelay';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './useHoverDelay';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './useHoverDelay';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './useHoverDelay';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type UseHoverDelayResult = {
|
|
2
|
+
/**
|
|
3
|
+
* Запускает отсчёт задержки. Повторный вызов перезапускает отсчёт
|
|
4
|
+
*/
|
|
5
|
+
start: () => void;
|
|
6
|
+
/**
|
|
7
|
+
* Отменяет отсчёт, если он не завершился
|
|
8
|
+
*/
|
|
9
|
+
cancel: () => void;
|
|
10
|
+
};
|
|
11
|
+
export type UseHoverDelayParams = {
|
|
12
|
+
/**
|
|
13
|
+
* Функция, вызывающаяся при hover-эффекте после задержки
|
|
14
|
+
*/
|
|
15
|
+
onHover: () => void;
|
|
16
|
+
/**
|
|
17
|
+
* Задержка вызова функции в мс
|
|
18
|
+
*/
|
|
19
|
+
delay: number;
|
|
20
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { useEffect, useRef } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Откладывает вызов на время удержания указателя над элементом.
|
|
4
|
+
*/
|
|
5
|
+
export const useHoverDelay = ({ delay, onHover, }) => {
|
|
6
|
+
const timeoutRef = useRef(undefined);
|
|
7
|
+
const savedOnHoverRef = useRef(onHover);
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
savedOnHoverRef.current = onHover;
|
|
10
|
+
});
|
|
11
|
+
const cancel = () => {
|
|
12
|
+
if (timeoutRef.current === undefined) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
clearTimeout(timeoutRef.current);
|
|
16
|
+
timeoutRef.current = undefined;
|
|
17
|
+
};
|
|
18
|
+
const start = () => {
|
|
19
|
+
cancel();
|
|
20
|
+
timeoutRef.current = setTimeout(() => {
|
|
21
|
+
timeoutRef.current = undefined;
|
|
22
|
+
savedOnHoverRef.current();
|
|
23
|
+
}, delay);
|
|
24
|
+
};
|
|
25
|
+
useEffect(() => cancel, []);
|
|
26
|
+
return { start, cancel };
|
|
27
|
+
};
|
|
@@ -1,15 +1,27 @@
|
|
|
1
|
-
|
|
1
|
+
import { type CSSProperties, type MouseEvent, type SyntheticEvent } from 'react';
|
|
2
2
|
import type { TagsListProps, TagValue } from '../types';
|
|
3
3
|
type UseLogicParams<TData extends TagValue> = TagsListProps<TData>;
|
|
4
|
-
export declare const useLogic: <TData extends TagValue>({ data, keyId, getOptionLabel, onChange, inputContainerRef, reservedWidth, }: UseLogicParams<TData>) => {
|
|
4
|
+
export declare const useLogic: <TData extends TagValue>({ data, keyId, isDisabled, getOptionLabel, onChange, onClick, inputContainerRef, fieldRef, reservedWidth, }: UseLogicParams<TData>) => {
|
|
5
5
|
visibleOptions: TData[];
|
|
6
6
|
hiddenCount: number;
|
|
7
7
|
showCounter: boolean;
|
|
8
8
|
tagsContainerRef: import("react").RefObject<HTMLDivElement | null>;
|
|
9
|
+
counterRef: import("react").RefObject<HTMLDivElement | null>;
|
|
9
10
|
getTagProps: (option: TData) => {
|
|
10
11
|
label: string | number;
|
|
11
12
|
shrinks: boolean;
|
|
12
13
|
onDelete: () => void;
|
|
13
14
|
};
|
|
15
|
+
isPopoverOpen: boolean;
|
|
16
|
+
isPopoverEnabled: boolean;
|
|
17
|
+
setPopoverContentRef: (node: HTMLDivElement | null) => void;
|
|
18
|
+
popoverContentCssVars: CSSProperties;
|
|
19
|
+
stopPopoverEventPropagation: (event: SyntheticEvent) => void;
|
|
20
|
+
popoverAnchorEl: HTMLElement | null;
|
|
21
|
+
closePopover: () => void;
|
|
22
|
+
startPopoverDelay: () => void;
|
|
23
|
+
cancelPopoverDelay: () => void;
|
|
24
|
+
handleTagClick: (event: MouseEvent<HTMLDivElement>) => void;
|
|
25
|
+
handleCounterClick: (event: MouseEvent<HTMLDivElement>) => void;
|
|
14
26
|
};
|
|
15
27
|
export {};
|
|
@@ -1,13 +1,38 @@
|
|
|
1
|
-
import { useEffect, useLayoutEffect, useRef, useState } from 'react';
|
|
1
|
+
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, } from 'react';
|
|
2
2
|
import { useTheme } from '../../theme/hooks/useTheme';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
3
|
+
import { useClickAwayEffect } from '../../useClickAwayEffect';
|
|
4
|
+
import { useNewToggle } from '../../useNewToggle';
|
|
5
|
+
import { useViewportType } from '../../useViewportType';
|
|
6
|
+
import { MIN_AVAILABLE_WIDTH, POPOVER_HOVER_DELAY } from '../constants';
|
|
7
|
+
import { calculatePopoverWidth, calculateVisibleTagsCount, getAvailableWidth, } from '../utils';
|
|
8
|
+
import { useHoverDelay } from './hooks/useHoverDelay';
|
|
9
|
+
export const useLogic = ({ data = [], keyId, isDisabled, getOptionLabel, onChange, onClick, inputContainerRef, fieldRef, reservedWidth = 0, }) => {
|
|
6
10
|
const [visibleOptions, setVisibleOptions] = useState([]);
|
|
7
11
|
const [hiddenCount, setHiddenCount] = useState(0);
|
|
12
|
+
const [isPopoverOpen, togglePopover] = useNewToggle(false);
|
|
13
|
+
const [isPopoverContentMounted, togglePopoverContentMounted] = useNewToggle(false);
|
|
14
|
+
/**
|
|
15
|
+
* Ширина окна и якорь позиционирования фиксируются на момент открытия
|
|
16
|
+
* и дальше не пересчитываются
|
|
17
|
+
*/
|
|
18
|
+
const [popoverWidth, setPopoverWidth] = useState(0);
|
|
19
|
+
const [popoverAnchorEl, setPopoverAnchorEl] = useState(null);
|
|
8
20
|
const tagsContainerRef = useRef(null);
|
|
9
21
|
const availableWidthRef = useRef(0);
|
|
22
|
+
const popoverContentRef = useRef(null);
|
|
23
|
+
const counterRef = useRef(null);
|
|
10
24
|
const theme = useTheme();
|
|
25
|
+
const { isMobile } = useViewportType();
|
|
26
|
+
const openPopover = () => {
|
|
27
|
+
const field = fieldRef.current;
|
|
28
|
+
if (isPopoverOpen || !field) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
setPopoverWidth(calculatePopoverWidth(field.getBoundingClientRect().width, data.map((item) => getOptionLabel(item).toString()), theme));
|
|
32
|
+
setPopoverAnchorEl(field);
|
|
33
|
+
togglePopover(true);
|
|
34
|
+
};
|
|
35
|
+
const closePopover = () => togglePopover(false);
|
|
11
36
|
/**
|
|
12
37
|
* Обновляет доступную ширину для расчета количества отображаемых тегов
|
|
13
38
|
*/
|
|
@@ -64,6 +89,7 @@ export const useLogic = ({ data = [], keyId, getOptionLabel, onChange, inputCont
|
|
|
64
89
|
if (!data.length) {
|
|
65
90
|
setVisibleOptions([]);
|
|
66
91
|
setHiddenCount(0);
|
|
92
|
+
closePopover();
|
|
67
93
|
return;
|
|
68
94
|
}
|
|
69
95
|
const resizeObserver = new ResizeObserver(() => {
|
|
@@ -102,11 +128,65 @@ export const useLogic = ({ data = [], keyId, getOptionLabel, onChange, inputCont
|
|
|
102
128
|
return { label, shrinks: false, onDelete };
|
|
103
129
|
};
|
|
104
130
|
const showCounter = hiddenCount > 0;
|
|
131
|
+
const { start: startPopoverDelay, cancel: cancelPopoverDelay } = useHoverDelay({ onHover: openPopover, delay: POPOVER_HOVER_DELAY });
|
|
132
|
+
const setPopoverContentRef = useCallback((node) => {
|
|
133
|
+
popoverContentRef.current = node;
|
|
134
|
+
togglePopoverContentMounted(Boolean(node));
|
|
135
|
+
}, []);
|
|
136
|
+
const popoverExcludedNodes = useMemo(() => [counterRef], []);
|
|
137
|
+
useClickAwayEffect({
|
|
138
|
+
ref: popoverContentRef,
|
|
139
|
+
onClickAway: closePopover,
|
|
140
|
+
isActive: isPopoverOpen && isPopoverContentMounted,
|
|
141
|
+
excludeNodes: popoverExcludedNodes,
|
|
142
|
+
});
|
|
143
|
+
const isPopoverEnabled = !isMobile && !isDisabled;
|
|
144
|
+
const handleTagClick = (event) => {
|
|
145
|
+
event.stopPropagation();
|
|
146
|
+
onClick?.(event);
|
|
147
|
+
};
|
|
148
|
+
const handleCounterClick = (event) => {
|
|
149
|
+
event.stopPropagation();
|
|
150
|
+
cancelPopoverDelay();
|
|
151
|
+
// На мобильной ширине и в заблокированном поле у счётчика прежнее поведение — список опций
|
|
152
|
+
if (!isPopoverEnabled) {
|
|
153
|
+
onClick?.(event);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
if (isPopoverOpen) {
|
|
157
|
+
closePopover();
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
openPopover();
|
|
161
|
+
};
|
|
162
|
+
/**
|
|
163
|
+
* Окно живёт в портале, но синтетические события React всплывают по дереву
|
|
164
|
+
* компонентов и доходят до обработчиков поля: у MUI Select это `handleMouseDown`,
|
|
165
|
+
* который переводит фокус на поле и открывает список, у TreeLike* — `onClick` поля
|
|
166
|
+
*/
|
|
167
|
+
const stopPopoverEventPropagation = (event) => {
|
|
168
|
+
event.stopPropagation();
|
|
169
|
+
};
|
|
170
|
+
const popoverContentCssVars = {
|
|
171
|
+
'--tags-list-popover-width': `${popoverWidth}px`,
|
|
172
|
+
};
|
|
105
173
|
return {
|
|
106
174
|
visibleOptions,
|
|
107
175
|
hiddenCount,
|
|
108
176
|
showCounter,
|
|
109
177
|
tagsContainerRef,
|
|
178
|
+
counterRef,
|
|
110
179
|
getTagProps,
|
|
180
|
+
isPopoverOpen,
|
|
181
|
+
isPopoverEnabled,
|
|
182
|
+
setPopoverContentRef,
|
|
183
|
+
popoverContentCssVars,
|
|
184
|
+
stopPopoverEventPropagation,
|
|
185
|
+
popoverAnchorEl,
|
|
186
|
+
closePopover,
|
|
187
|
+
startPopoverDelay,
|
|
188
|
+
cancelPopoverDelay,
|
|
189
|
+
handleTagClick,
|
|
190
|
+
handleCounterClick,
|
|
111
191
|
};
|
|
112
192
|
};
|