@astral/ui 4.36.1 → 4.37.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (194) hide show
  1. package/components/Accordion/styles.d.ts +1 -0
  2. package/components/Alert/styles.d.ts +2 -0
  3. package/components/AutoSaveIndicator/styles.d.ts +2 -0
  4. package/components/Autocomplete/Autocomplete.d.ts +1 -1
  5. package/components/Autocomplete/Autocomplete.js +53 -15
  6. package/components/Autocomplete/constants.d.ts +6 -0
  7. package/components/Autocomplete/constants.js +7 -0
  8. package/components/Autocomplete/styles.js +15 -1
  9. package/components/Autocomplete/useLogic/useLogic.d.ts +2 -1
  10. package/components/Autocomplete/useLogic/useLogic.js +11 -2
  11. package/components/BottomDrawer/styles.d.ts +1 -0
  12. package/components/Chip/styles.d.ts +1 -0
  13. package/components/CodeField/styles.d.ts +1 -0
  14. package/components/CollapsibleTypography/CollapsibleTypography.d.ts +1 -0
  15. package/components/CollapsibleTypography/styles.d.ts +1 -0
  16. package/components/ConfirmAction/styles.d.ts +1 -0
  17. package/components/CopyTypography/styles.d.ts +1 -0
  18. package/components/CopyTypography/useLogic/useLogic.d.ts +1 -0
  19. package/components/DashboardSidebarPopover/styles.d.ts +1 -0
  20. package/components/DataGridPagination/styles.d.ts +1 -0
  21. package/components/DataGridPaginationContainer/styles.d.ts +1 -0
  22. package/components/DatePicker/DateCalendar/DateCalendarHead/styles.d.ts +1 -0
  23. package/components/Description/Value/styles.d.ts +2 -0
  24. package/components/DescriptionList/styles.d.ts +1 -0
  25. package/components/Fieldset/styles.d.ts +2 -0
  26. package/components/Filename/styles.d.ts +1 -0
  27. package/components/FlowButton/styles.d.ts +1 -0
  28. package/components/JsonViewer/NodeValue/styles.d.ts +3 -0
  29. package/components/LegacyNotification/NotificationTemplate/styles.d.ts +2 -0
  30. package/components/MaskField/MaskField.js +2 -2
  31. package/components/MaskField/styles.d.ts +2 -0
  32. package/components/MaskField/styles.js +5 -0
  33. package/components/MenuGroup/styles.d.ts +1 -0
  34. package/components/MenuOrganization/OrganizationButton/styles.d.ts +1 -0
  35. package/components/MenuOrganization/OrganizationGroup/styles.d.ts +1 -0
  36. package/components/MenuOrganization/styles.d.ts +1 -0
  37. package/components/MinimalisticPagination/styles.d.ts +1 -0
  38. package/components/NavMenu/Item/ItemButton/styles.d.ts +1 -0
  39. package/components/NotFoundPage/styles.d.ts +2 -0
  40. package/components/Notification/NotificationTemplate/styles.d.ts +2 -0
  41. package/components/NotificationList/ListItem/styles.d.ts +2 -0
  42. package/components/OverflowTypography/OverflowTypography.d.ts +1 -0
  43. package/components/OverflowTypography/styles.d.ts +2 -0
  44. package/components/PageContent/PageContentHeader/Title/styles.d.ts +1 -0
  45. package/components/PageHeader/HeaderContent/Description/styles.d.ts +1 -0
  46. package/components/PageHeader/Title/styles.d.ts +1 -0
  47. package/components/Pagination/PaginationItem/styles.d.ts +1 -0
  48. package/components/PinButton/styles.d.ts +1 -0
  49. package/components/ProductSwitcher/Content/styles.d.ts +1 -0
  50. package/components/TagsList/Tag/Tag.d.ts +1 -1
  51. package/components/TagsList/Tag/constants.d.ts +1 -0
  52. package/components/TagsList/Tag/constants.js +1 -0
  53. package/components/TagsList/Tag/index.d.ts +1 -0
  54. package/components/TagsList/Tag/index.js +1 -0
  55. package/components/TagsList/Tag/styles.js +2 -0
  56. package/components/TagsList/TagsList.js +6 -6
  57. package/components/TagsList/constants.d.ts +2 -0
  58. package/components/TagsList/constants.js +2 -0
  59. package/components/TagsList/styles.js +5 -1
  60. package/components/TagsList/types.d.ts +14 -5
  61. package/components/TagsList/useLogic/useLogic.d.ts +5 -5
  62. package/components/TagsList/useLogic/useLogic.js +70 -110
  63. package/components/TagsList/utils/calculateVisibleTagsCount/calculateVisibleTagsCount.d.ts +6 -0
  64. package/components/TagsList/utils/calculateVisibleTagsCount/calculateVisibleTagsCount.js +35 -0
  65. package/components/TagsList/utils/calculateVisibleTagsCount/index.d.ts +1 -0
  66. package/components/TagsList/utils/calculateVisibleTagsCount/index.js +1 -0
  67. package/components/TagsList/utils/getAvailableWidth/getAvailableWidth.d.ts +1 -0
  68. package/components/TagsList/utils/getAvailableWidth/getAvailableWidth.js +7 -0
  69. package/components/TagsList/utils/getAvailableWidth/index.d.ts +1 -0
  70. package/components/TagsList/utils/getAvailableWidth/index.js +1 -0
  71. package/components/TagsList/utils/getKey/getKey.d.ts +1 -1
  72. package/components/TagsList/utils/getKey/getKey.js +6 -3
  73. package/components/TagsList/utils/getTagWidth/getTagWidth.d.ts +2 -0
  74. package/components/TagsList/utils/getTagWidth/getTagWidth.js +21 -0
  75. package/components/TagsList/utils/getTagWidth/index.d.ts +1 -0
  76. package/components/TagsList/utils/getTagWidth/index.js +1 -0
  77. package/components/TagsList/utils/index.d.ts +3 -0
  78. package/components/TagsList/utils/index.js +3 -0
  79. package/components/TextField/TextField.js +6 -5
  80. package/components/TextField/constants.d.ts +1 -0
  81. package/components/TextField/constants.js +1 -0
  82. package/components/TextField/styles.js +4 -0
  83. package/components/Tree/TreeItem/styles.d.ts +2 -0
  84. package/components/TreeLikeAsyncAutocomplete/Input/Input.js +1 -1
  85. package/components/Typography/Typography.d.ts +1 -0
  86. package/components/Typography/Typography.js +6 -2
  87. package/components/Typography/constants.d.ts +3 -0
  88. package/components/Typography/constants.js +3 -0
  89. package/components/Typography/styles.js +5 -0
  90. package/components/Typography/types.d.ts +4 -0
  91. package/components/WelcomeScreen/styles.d.ts +2 -0
  92. package/components/fileUploading/FileInfo/styles.d.ts +1 -0
  93. package/components/placeholders/Placeholder/styles.d.ts +2 -0
  94. package/hook-form/EditableText/EditingForm/styles.d.ts +1 -0
  95. package/hook-form/EditableText/styles.d.ts +1 -0
  96. package/node/components/Accordion/styles.d.ts +1 -0
  97. package/node/components/Alert/styles.d.ts +2 -0
  98. package/node/components/AutoSaveIndicator/styles.d.ts +2 -0
  99. package/node/components/Autocomplete/Autocomplete.d.ts +1 -1
  100. package/node/components/Autocomplete/Autocomplete.js +51 -13
  101. package/node/components/Autocomplete/constants.d.ts +6 -0
  102. package/node/components/Autocomplete/constants.js +8 -1
  103. package/node/components/Autocomplete/styles.js +15 -1
  104. package/node/components/Autocomplete/useLogic/useLogic.d.ts +2 -1
  105. package/node/components/Autocomplete/useLogic/useLogic.js +10 -1
  106. package/node/components/BottomDrawer/styles.d.ts +1 -0
  107. package/node/components/Chip/styles.d.ts +1 -0
  108. package/node/components/CodeField/styles.d.ts +1 -0
  109. package/node/components/CollapsibleTypography/CollapsibleTypography.d.ts +1 -0
  110. package/node/components/CollapsibleTypography/styles.d.ts +1 -0
  111. package/node/components/ConfirmAction/styles.d.ts +1 -0
  112. package/node/components/CopyTypography/styles.d.ts +1 -0
  113. package/node/components/CopyTypography/useLogic/useLogic.d.ts +1 -0
  114. package/node/components/DashboardSidebarPopover/styles.d.ts +1 -0
  115. package/node/components/DataGridPagination/styles.d.ts +1 -0
  116. package/node/components/DataGridPaginationContainer/styles.d.ts +1 -0
  117. package/node/components/DatePicker/DateCalendar/DateCalendarHead/styles.d.ts +1 -0
  118. package/node/components/Description/Value/styles.d.ts +2 -0
  119. package/node/components/DescriptionList/styles.d.ts +1 -0
  120. package/node/components/Fieldset/styles.d.ts +2 -0
  121. package/node/components/Filename/styles.d.ts +1 -0
  122. package/node/components/FlowButton/styles.d.ts +1 -0
  123. package/node/components/JsonViewer/NodeValue/styles.d.ts +3 -0
  124. package/node/components/LegacyNotification/NotificationTemplate/styles.d.ts +2 -0
  125. package/node/components/MaskField/MaskField.js +2 -2
  126. package/node/components/MaskField/styles.d.ts +2 -0
  127. package/node/components/MaskField/styles.js +8 -0
  128. package/node/components/MenuGroup/styles.d.ts +1 -0
  129. package/node/components/MenuOrganization/OrganizationButton/styles.d.ts +1 -0
  130. package/node/components/MenuOrganization/OrganizationGroup/styles.d.ts +1 -0
  131. package/node/components/MenuOrganization/styles.d.ts +1 -0
  132. package/node/components/MinimalisticPagination/styles.d.ts +1 -0
  133. package/node/components/NavMenu/Item/ItemButton/styles.d.ts +1 -0
  134. package/node/components/NotFoundPage/styles.d.ts +2 -0
  135. package/node/components/Notification/NotificationTemplate/styles.d.ts +2 -0
  136. package/node/components/NotificationList/ListItem/styles.d.ts +2 -0
  137. package/node/components/OverflowTypography/OverflowTypography.d.ts +1 -0
  138. package/node/components/OverflowTypography/styles.d.ts +2 -0
  139. package/node/components/PageContent/PageContentHeader/Title/styles.d.ts +1 -0
  140. package/node/components/PageHeader/HeaderContent/Description/styles.d.ts +1 -0
  141. package/node/components/PageHeader/Title/styles.d.ts +1 -0
  142. package/node/components/Pagination/PaginationItem/styles.d.ts +1 -0
  143. package/node/components/PinButton/styles.d.ts +1 -0
  144. package/node/components/ProductSwitcher/Content/styles.d.ts +1 -0
  145. package/node/components/TagsList/Tag/Tag.d.ts +1 -1
  146. package/node/components/TagsList/Tag/constants.d.ts +1 -0
  147. package/node/components/TagsList/Tag/constants.js +4 -0
  148. package/node/components/TagsList/Tag/index.d.ts +1 -0
  149. package/node/components/TagsList/Tag/index.js +1 -0
  150. package/node/components/TagsList/Tag/styles.js +2 -0
  151. package/node/components/TagsList/TagsList.js +6 -6
  152. package/node/components/TagsList/constants.d.ts +2 -0
  153. package/node/components/TagsList/constants.js +5 -0
  154. package/node/components/TagsList/styles.js +5 -1
  155. package/node/components/TagsList/types.d.ts +14 -5
  156. package/node/components/TagsList/useLogic/useLogic.d.ts +5 -5
  157. package/node/components/TagsList/useLogic/useLogic.js +70 -110
  158. package/node/components/TagsList/utils/calculateVisibleTagsCount/calculateVisibleTagsCount.d.ts +6 -0
  159. package/node/components/TagsList/utils/calculateVisibleTagsCount/calculateVisibleTagsCount.js +39 -0
  160. package/node/components/TagsList/utils/calculateVisibleTagsCount/index.d.ts +1 -0
  161. package/node/components/TagsList/utils/calculateVisibleTagsCount/index.js +5 -0
  162. package/node/components/TagsList/utils/getAvailableWidth/getAvailableWidth.d.ts +1 -0
  163. package/node/components/TagsList/utils/getAvailableWidth/getAvailableWidth.js +11 -0
  164. package/node/components/TagsList/utils/getAvailableWidth/index.d.ts +1 -0
  165. package/node/components/TagsList/utils/getAvailableWidth/index.js +5 -0
  166. package/node/components/TagsList/utils/getKey/getKey.d.ts +1 -1
  167. package/node/components/TagsList/utils/getKey/getKey.js +6 -3
  168. package/node/components/TagsList/utils/getTagWidth/getTagWidth.d.ts +2 -0
  169. package/node/components/TagsList/utils/getTagWidth/getTagWidth.js +25 -0
  170. package/node/components/TagsList/utils/getTagWidth/index.d.ts +1 -0
  171. package/node/components/TagsList/{public.js → utils/getTagWidth/index.js} +1 -2
  172. package/node/components/TagsList/utils/index.d.ts +3 -0
  173. package/node/components/TagsList/utils/index.js +7 -1
  174. package/node/components/TextField/TextField.js +6 -5
  175. package/node/components/TextField/constants.d.ts +1 -0
  176. package/node/components/TextField/constants.js +1 -0
  177. package/node/components/TextField/styles.js +4 -0
  178. package/node/components/Tree/TreeItem/styles.d.ts +2 -0
  179. package/node/components/TreeLikeAsyncAutocomplete/Input/Input.js +1 -1
  180. package/node/components/Typography/Typography.d.ts +1 -0
  181. package/node/components/Typography/Typography.js +6 -2
  182. package/node/components/Typography/constants.d.ts +3 -0
  183. package/node/components/Typography/constants.js +6 -0
  184. package/node/components/Typography/styles.js +5 -0
  185. package/node/components/Typography/types.d.ts +4 -0
  186. package/node/components/WelcomeScreen/styles.d.ts +2 -0
  187. package/node/components/fileUploading/FileInfo/styles.d.ts +1 -0
  188. package/node/components/placeholders/Placeholder/styles.d.ts +2 -0
  189. package/node/hook-form/EditableText/EditingForm/styles.d.ts +1 -0
  190. package/node/hook-form/EditableText/styles.d.ts +1 -0
  191. package/package.json +1 -1
  192. package/components/TagsList/public.d.ts +0 -2
  193. package/components/TagsList/public.js +0 -2
  194. package/node/components/TagsList/public.d.ts +0 -2
@@ -10,6 +10,7 @@ export declare const Title: import("../../styled").StyledComponent<import("../..
10
10
  colorIntensity?: import("../../Typography").Intensity | undefined;
11
11
  component?: import("../../Typography/types").ComponentProp | undefined;
12
12
  isUpperCase?: boolean | undefined;
13
+ withoutCalt?: boolean | undefined;
13
14
  } & import("react").HTMLAttributes<HTMLParagraphElement> & import("react").RefAttributes<HTMLSpanElement> & {
14
15
  theme?: import("@emotion/react").Theme | undefined;
15
16
  }, {}, {}>;
@@ -19,6 +20,7 @@ export declare const DateText: import("../../styled").StyledComponent<import("..
19
20
  colorIntensity?: import("../../Typography").Intensity | undefined;
20
21
  component?: import("../../Typography/types").ComponentProp | undefined;
21
22
  isUpperCase?: boolean | undefined;
23
+ withoutCalt?: boolean | undefined;
22
24
  } & import("react").HTMLAttributes<HTMLParagraphElement> & import("react").RefAttributes<HTMLSpanElement> & {
23
25
  theme?: import("@emotion/react").Theme | undefined;
24
26
  }, {}, {}>;
@@ -342,6 +342,7 @@ export declare const OverflowTypography: import("react").ForwardRefExoticCompone
342
342
  colorIntensity?: import("../Typography").Intensity | undefined;
343
343
  component?: import("../Typography/types").ComponentProp | undefined;
344
344
  isUpperCase?: boolean | undefined;
345
+ withoutCalt?: boolean | undefined;
345
346
  } & import("react").HTMLAttributes<HTMLParagraphElement> & {
346
347
  children?: import("react").ReactNode;
347
348
  } & import("react").RefAttributes<HTMLElement>>;
@@ -9,6 +9,7 @@ export declare const StyledTypography: import("../styled").StyledComponent<impor
9
9
  colorIntensity?: import("../Typography").Intensity | undefined;
10
10
  component?: import("../Typography/types").ComponentProp | undefined;
11
11
  isUpperCase?: boolean | undefined;
12
+ withoutCalt?: boolean | undefined;
12
13
  } & import("react").HTMLAttributes<HTMLParagraphElement> & import("react").RefAttributes<HTMLSpanElement> & {
13
14
  theme?: import("@emotion/react").Theme | undefined;
14
15
  } & OverflowTypographyWrapperProps, {}, {}>;
@@ -18,6 +19,7 @@ export declare const Wrapper: import("../styled").StyledComponent<import("../Typ
18
19
  colorIntensity?: import("../Typography").Intensity | undefined;
19
20
  component?: import("../Typography/types").ComponentProp | undefined;
20
21
  isUpperCase?: boolean | undefined;
22
+ withoutCalt?: boolean | undefined;
21
23
  } & import("react").HTMLAttributes<HTMLParagraphElement> & import("react").RefAttributes<HTMLSpanElement> & {
22
24
  theme?: import("@emotion/react").Theme | undefined;
23
25
  } & {
@@ -5,6 +5,7 @@ export declare const TitleWrapper: import("../../../styled").StyledComponent<imp
5
5
  colorIntensity?: import("../../../Typography").Intensity | undefined;
6
6
  component?: import("../../../Typography/types").ComponentProp | undefined;
7
7
  isUpperCase?: boolean | undefined;
8
+ withoutCalt?: boolean | undefined;
8
9
  } & import("react").HTMLAttributes<HTMLParagraphElement> & import("react").RefAttributes<HTMLSpanElement> & {
9
10
  theme?: import("@emotion/react").Theme | undefined;
10
11
  }, {}, {}>;
@@ -5,6 +5,7 @@ export declare const StyledTypography: import("../../../styled").StyledComponent
5
5
  colorIntensity?: import("../../../Typography").Intensity | undefined;
6
6
  component?: import("../../../Typography/types").ComponentProp | undefined;
7
7
  isUpperCase?: boolean | undefined;
8
+ withoutCalt?: boolean | undefined;
8
9
  } & import("react").HTMLAttributes<HTMLParagraphElement> & import("react").RefAttributes<HTMLSpanElement> & {
9
10
  theme?: import("@emotion/react").Theme | undefined;
10
11
  }, {}, {}>;
@@ -5,6 +5,7 @@ export declare const TitleWrapper: import("../../styled").StyledComponent<import
5
5
  colorIntensity?: import("../../Typography").Intensity | undefined;
6
6
  component?: import("../../Typography/types").ComponentProp | undefined;
7
7
  isUpperCase?: boolean | undefined;
8
+ withoutCalt?: boolean | undefined;
8
9
  } & import("react").HTMLAttributes<HTMLParagraphElement> & import("react").RefAttributes<HTMLSpanElement> & {
9
10
  theme?: import("@emotion/react").Theme | undefined;
10
11
  } & {
@@ -5,6 +5,7 @@ export declare const Ellipsis: import("../../styled").StyledComponent<import("..
5
5
  colorIntensity?: import("../../Typography").Intensity | undefined;
6
6
  component?: import("../../Typography/types").ComponentProp | undefined;
7
7
  isUpperCase?: boolean | undefined;
8
+ withoutCalt?: boolean | undefined;
8
9
  } & import("react").HTMLAttributes<HTMLParagraphElement> & import("react").RefAttributes<HTMLSpanElement> & {
9
10
  theme?: import("@emotion/react").Theme | undefined;
10
11
  } & {
@@ -14,6 +14,7 @@ export declare const Content: import("../styled").StyledComponent<import("../Typ
14
14
  colorIntensity?: import("../Typography").Intensity | undefined;
15
15
  component?: import("../Typography/types").ComponentProp | undefined;
16
16
  isUpperCase?: boolean | undefined;
17
+ withoutCalt?: boolean | undefined;
17
18
  } & import("react").HTMLAttributes<HTMLParagraphElement> & import("react").RefAttributes<HTMLSpanElement> & {
18
19
  theme?: import("@emotion/react").Theme | undefined;
19
20
  }, {}, {}>;
@@ -19,6 +19,7 @@ export declare const ProductName: import("../../styled").StyledComponent<import(
19
19
  colorIntensity?: import("../../Typography").Intensity | undefined;
20
20
  component?: import("../../Typography/types").ComponentProp | undefined;
21
21
  isUpperCase?: boolean | undefined;
22
+ withoutCalt?: boolean | undefined;
22
23
  } & import("react").HTMLAttributes<HTMLParagraphElement> & import("react").RefAttributes<HTMLSpanElement> & {
23
24
  theme?: import("@emotion/react").Theme | undefined;
24
25
  }, {}, {}>;
@@ -20,7 +20,7 @@ export type TagProps = {
20
20
  /**
21
21
  * Хендлер клика по тегу
22
22
  */
23
- onClick: (value: MouseEvent<HTMLDivElement>) => void;
23
+ onClick?: (value: MouseEvent<HTMLDivElement>) => void;
24
24
  /**
25
25
  * Название класса, применяется к корневому компоненту
26
26
  */
@@ -0,0 +1 @@
1
+ export declare const MAX_TAG_WIDTH = "246px";
@@ -0,0 +1 @@
1
+ export const MAX_TAG_WIDTH = '246px';
@@ -1 +1,2 @@
1
1
  export * from './Tag';
2
+ export * from './constants';
@@ -1 +1,2 @@
1
1
  export * from './Tag';
2
+ export * from './constants';
@@ -3,6 +3,8 @@ import { Tag, tagClassnames } from '../../Tag';
3
3
  export const StyledTag = styled(Tag, {
4
4
  shouldForwardProp: (prop) => prop !== '$shrinks',
5
5
  }) `
6
+ overflow: hidden;
7
+
6
8
  /* 4em ширина необходима для отображения двух букв и избежания перекрытия кнопкой сброса всего текста тега */
7
9
  min-width: ${({ $shrinks }) => ($shrinks ? 'calc(2em + 20px)' : 'unset')};
8
10
  max-width: 246px;
@@ -8,10 +8,10 @@ import { getKey } from './utils';
8
8
  * Не предназначен для использования в продуктах, не экспортируется из пакета
9
9
  */
10
10
  export const TagsList = (props) => {
11
- const { maxItems, tagsContainerRef, visibleOptions, getTagProps } = useLogic(props);
12
- const { className, data, keyId, isDisabled, onClick } = props;
13
- return (_jsxs(Wrapper, { className: className, ref: tagsContainerRef, children: [visibleOptions?.map((option, index) => {
14
- const tagProps = getTagProps(option, index);
15
- return (_jsx(Tag, { isDisabled: isDisabled, onClick: onClick, ...tagProps }, getKey(option, keyId)));
16
- }), data && maxItems < data.length && (_jsx(CounterTag, { isDisabled: isDisabled, label: `+${data.length - maxItems}`, onClick: onClick }, "more"))] }));
11
+ const { hiddenCount, tagsContainerRef, visibleOptions, getTagProps, showCounter, } = useLogic(props);
12
+ const { className, keyId, isDisabled, onClick, getOptionLabel } = props;
13
+ return (_jsxs(Wrapper, { className: className, ref: tagsContainerRef, children: [visibleOptions?.map((option) => {
14
+ const tagProps = getTagProps(option);
15
+ return (_jsx(Tag, { isDisabled: isDisabled, onClick: onClick, ...tagProps }, getKey(option, keyId, getOptionLabel)));
16
+ }), showCounter && (_jsx(CounterTag, { isDisabled: isDisabled, label: `+${hiddenCount}`, onClick: onClick }, "more"))] }));
17
17
  };
@@ -0,0 +1,2 @@
1
+ export declare const MIN_AVAILABLE_WIDTH = 50;
2
+ export declare const GAP_BETWEEN_TAGS = 4;
@@ -0,0 +1,2 @@
1
+ export const MIN_AVAILABLE_WIDTH = 50;
2
+ export const GAP_BETWEEN_TAGS = 4; // 4px
@@ -1,11 +1,15 @@
1
1
  import { styled } from '../styled';
2
2
  import { tagClassnames } from '../Tag';
3
+ import { GAP_BETWEEN_TAGS } from './constants';
3
4
  import { Tag } from './Tag';
4
5
  export const Wrapper = styled.div `
6
+ overflow: hidden;
5
7
  display: flex;
6
- column-gap: ${({ theme }) => theme.spacing(1)};
8
+ column-gap: ${GAP_BETWEEN_TAGS}px;
7
9
  `;
8
10
  export const CounterTag = styled(Tag) `
11
+ overflow: unset;
12
+
9
13
  .${tagClassnames.label} {
10
14
  min-width: unset;
11
15
  }
@@ -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: TData extends string ? never : keyof TData;
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: (value: MouseEvent<HTMLDivElement>) => void;
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, index: number) => {
9
+ getTagProps: (option: TData) => {
10
10
  label: string | number;
11
11
  shrinks: boolean;
12
12
  onDelete: () => void;
@@ -1,145 +1,105 @@
1
1
  import { useEffect, useLayoutEffect, useRef, useState } from 'react';
2
2
  import { useTheme } from '../../theme/hooks/useTheme';
3
- export const useLogic = ({ data = [], keyId, getOptionLabel, onChange, }) => {
4
- // Сколько тегов можно отобразить в инпуте
5
- const [maxItems, setMaxItems] = useState(1);
6
- const ignoreResizeRef = useRef(false);
3
+ import { MIN_AVAILABLE_WIDTH } from '../constants';
4
+ import { calculateVisibleTagsCount, getAvailableWidth } from '../utils';
5
+ export const useLogic = ({ data = [], keyId, getOptionLabel, onChange, inputContainerRef, reservedWidth = 0, }) => {
6
+ const [visibleOptions, setVisibleOptions] = useState([]);
7
+ const [hiddenCount, setHiddenCount] = useState(0);
7
8
  const tagsContainerRef = useRef(null);
9
+ const availableWidthRef = useRef(0);
8
10
  const theme = useTheme();
9
11
  /**
10
- * Определяет, сколько тегов можно отобразить в строке,
11
- * учитывая ширину контейнера и промежутки (gap) между тегами.
12
- *
13
- * @param container - DOM-элемент контейнера с тегами
14
- * @param gap - расстояние между тегами (например, 4px)
15
- * @param padding - отступ внутри тега
16
- * @returns количество тегов, которые помещаются без переполнения
12
+ * Обновляет доступную ширину для расчета количества отображаемых тегов
17
13
  */
18
- const getTagsCountToAdd = (container, gap, padding) => {
19
- const tags = Array.from(container.children);
20
- // Если нет ни одного тега, сразу возвращаем 0
21
- if (tags.length === 0) {
22
- return 0;
14
+ const updateAvailableWidth = () => {
15
+ const target = inputContainerRef?.current ?? tagsContainerRef.current;
16
+ if (target) {
17
+ availableWidthRef.current = getAvailableWidth(target, reservedWidth);
23
18
  }
24
- // Преобразуем значение из темы в число
25
- const gapValue = parseInt(gap, 10);
26
- const paddingValue = parseInt(padding, 10);
27
- let totalWidth = 0; // Накопленная ширина всех тегов + gap
28
- let lastFittingIndex = tags.length; // Индекс, до которого теги помещаются
29
- for (let i = 0; i < tags.length; i++) {
30
- const tag = tags[i];
31
- const contentEl = tag.firstElementChild;
32
- // Полная ширина элемента (включая margin/padding/border)
33
- const tagWidth = tag.clientWidth;
34
- // gap учитывается, начиная со второго тега
35
- const currentGap = i > 0 ? gapValue : 0;
36
- // Проверяем, переполнен ли текст внутри тега (например, обрезался)
37
- const isContentOverflowing = contentEl?.scrollWidth > contentEl?.clientWidth;
38
- // Если добавление текущего тега превышает ширину контейнера
39
- // или если сам контент внутри тега не помещается
40
- if (totalWidth + currentGap + tagWidth > container.clientWidth ||
41
- isContentOverflowing) {
42
- lastFittingIndex = i;
43
- break;
44
- }
45
- // Увеличиваем суммарную ширину
46
- totalWidth += currentGap + tagWidth + paddingValue;
47
- }
48
- // Если даже первый тег не влезает, всё равно показываем один тег
49
- if (lastFittingIndex === 0 && tags.length > 0) {
50
- return 1;
51
- }
52
- return lastFittingIndex;
53
19
  };
54
- /**
55
- * Пересчитывает максимальное количество тегов (maxItems),
56
- * которые помещаются в строку контейнера без переполнения.
57
- */
58
20
  const recomputeMaxItems = () => {
59
- const containerEl = tagsContainerRef.current;
60
- // Если контейнер или данные не заданы — прекращаем
61
- if (!containerEl || !data?.length) {
21
+ if (data.length === 0) {
22
+ setVisibleOptions([]);
23
+ setHiddenCount(0);
62
24
  return;
63
25
  }
64
- // Берём первый тег как шаблон (для клонирования)
65
- const tagTemplate = containerEl.children[0];
66
- if (!tagTemplate) {
26
+ const hasNoInputContainer = !inputContainerRef?.current;
27
+ const isZeroWidth = availableWidthRef.current === 0;
28
+ const isSmallWidth = availableWidthRef.current < MIN_AVAILABLE_WIDTH;
29
+ // Если нет inputContainerRef и доступная ширина слишком мала или не вычислена - показываем первый тег и счетчик(если есть)
30
+ if (hasNoInputContainer && (isZeroWidth || isSmallWidth)) {
31
+ setVisibleOptions(data.slice(0, 1));
32
+ setHiddenCount(data.length - 1);
67
33
  return;
68
34
  }
69
- // Создаём скрытый клон-контейнер, чтобы измерить ширину вне DOM-окружения
70
- const clone = document.createElement('div');
71
- // Задаем стили для клон-контейнера
72
- clone.style.cssText = `
73
- visibility: hidden;
74
- position: absolute;
75
- width: ${containerEl.clientWidth}px;
76
- white-space: nowrap;
77
- `;
78
- // На основе шаблона создаём копии тегов для всех элементов data
79
- data.forEach((option) => {
80
- const tagClone = tagTemplate.cloneNode(true);
81
- const contentEl = tagClone.firstElementChild;
82
- if (contentEl) {
83
- // Подставляем текст соответствующего option
84
- contentEl.textContent = getOptionLabel(option).toString();
85
- // Включаем горизонтальный скролл, чтобы можно было определить overflow
86
- contentEl.style.overflowX = 'auto';
87
- }
88
- clone.appendChild(tagClone);
89
- });
90
- // Добавляем клон-контейнер в DOM, чтобы получить размеры
91
- document.body.appendChild(clone);
92
- // Вычисляем, сколько тегов влезает с учётом gap и padding
93
- const visibleCount = getTagsCountToAdd(clone, theme.spacing(1), theme.spacing(2));
94
- // Сохраняем результат в стейт
95
- setMaxItems(visibleCount);
96
- // Удаляем клон из DOM
97
- document.body.removeChild(clone);
98
- };
99
- useLayoutEffect(() => {
100
- if (typeof window === 'undefined' || !data || !data.length) {
35
+ // Если нет inputContainerRef и данных всего 1, показываем его даже при малой ширине (fallback)
36
+ if (hasNoInputContainer && data.length === 1) {
37
+ setVisibleOptions(data.slice(0, 1));
38
+ setHiddenCount(0);
39
+ return;
40
+ }
41
+ if (isSmallWidth) {
42
+ setVisibleOptions([]);
43
+ setHiddenCount(data.length);
44
+ }
45
+ // Расчет количества отображаемых тегов
46
+ const labels = data.map((item) => getOptionLabel(item).toString());
47
+ const visibleCount = calculateVisibleTagsCount(labels, availableWidthRef.current, theme);
48
+ const finalCount = Math.min(visibleCount, data.length);
49
+ if (finalCount === 0 && hasNoInputContainer) {
50
+ setVisibleOptions(data.slice(0, 1));
51
+ setHiddenCount(data.length - 1);
101
52
  return;
102
53
  }
54
+ setVisibleOptions(data.slice(0, finalCount));
55
+ setHiddenCount(data.length - finalCount);
56
+ };
57
+ useEffect(() => {
58
+ updateAvailableWidth();
59
+ }, [reservedWidth]);
60
+ useLayoutEffect(() => {
103
61
  recomputeMaxItems();
104
- // Не пересчитываем ширину контейнера, так как сами ее модифицировали
105
- ignoreResizeRef.current = true;
106
- }, [data]);
62
+ }, []);
107
63
  useEffect(() => {
108
- if (typeof window === 'undefined' || !data || !data.length) {
64
+ if (!data.length) {
65
+ setVisibleOptions([]);
66
+ setHiddenCount(0);
109
67
  return;
110
68
  }
111
- if (!tagsContainerRef.current) {
112
- throw new Error('Tags container ref is not set');
113
- }
114
- // Пересчитываем maxItems при ресайзе контейнера
115
- const observer = new ResizeObserver(() => {
116
- if (ignoreResizeRef.current) {
117
- ignoreResizeRef.current = false;
118
- return;
119
- }
69
+ const resizeObserver = new ResizeObserver(() => {
70
+ updateAvailableWidth();
120
71
  recomputeMaxItems();
121
72
  });
122
- observer.observe(tagsContainerRef.current);
123
- return () => observer.disconnect();
73
+ const target = inputContainerRef?.current ?? tagsContainerRef.current;
74
+ if (!target) {
75
+ return;
76
+ }
77
+ resizeObserver.observe(target);
78
+ return () => {
79
+ resizeObserver.disconnect();
80
+ };
124
81
  }, [data]);
125
- const getTagProps = (option, index) => {
82
+ const getTagProps = (option) => {
126
83
  const label = getOptionLabel(option);
127
- const shrinks = index === maxItems - 1 && maxItems <= data.length;
128
84
  const onDelete = () => {
129
- const newValue = data?.filter((value) => {
85
+ const newValue = data.filter((value) => {
130
86
  if (typeof value === 'string') {
131
87
  return value !== option;
132
88
  }
133
- return value[keyId] !== option[keyId];
89
+ if (keyId) {
90
+ return value[keyId] !== option[keyId];
91
+ }
92
+ return getOptionLabel(value) !== getOptionLabel(option);
134
93
  });
135
- onChange(newValue?.length ? newValue : []);
94
+ onChange(newValue.length ? newValue : []);
136
95
  };
137
- return { label, shrinks, onDelete };
96
+ return { label, shrinks: false, onDelete };
138
97
  };
139
- const visibleOptions = data?.slice(0, maxItems);
98
+ const showCounter = hiddenCount > 0;
140
99
  return {
141
- maxItems,
142
100
  visibleOptions,
101
+ hiddenCount,
102
+ showCounter,
143
103
  tagsContainerRef,
144
104
  getTagProps,
145
105
  };
@@ -0,0 +1,6 @@
1
+ import type { Theme } from '../../../theme/types';
2
+ /**
3
+ * Вычисляет количество тегов, которые могут поместиться в доступную ширину
4
+ * с учетом пробелов между тегами и счетчика оставшихся элементов
5
+ */
6
+ export declare const calculateVisibleTagsCount: (tagLabels: string[], availableWidth: number, theme: Theme) => number;
@@ -0,0 +1,35 @@
1
+ import { GAP_BETWEEN_TAGS, MIN_AVAILABLE_WIDTH } from '../../constants';
2
+ import { getTagWidth } from '../getTagWidth';
3
+ /**
4
+ * Вычисляет количество тегов, которые могут поместиться в доступную ширину
5
+ * с учетом пробелов между тегами и счетчика оставшихся элементов
6
+ */
7
+ export const calculateVisibleTagsCount = (tagLabels, availableWidth, theme) => {
8
+ if (!tagLabels.length || availableWidth <= 0) {
9
+ return 0;
10
+ }
11
+ const tagWidths = tagLabels.map((label) => getTagWidth(label, theme));
12
+ const canFitTagAtIndex = (tagIndex, accumulatedWidth) => {
13
+ const isFirstTag = tagIndex === 0;
14
+ const gapWidth = isFirstTag ? 0 : GAP_BETWEEN_TAGS;
15
+ const tagsAfterCurrent = tagLabels.length - (tagIndex + 1);
16
+ const counterTagWidth = tagsAfterCurrent > 0
17
+ ? getTagWidth(`+${tagsAfterCurrent}`, theme, true) + GAP_BETWEEN_TAGS
18
+ : 0;
19
+ const totalWidthWithTag = accumulatedWidth + gapWidth + tagWidths[tagIndex];
20
+ return totalWidthWithTag + counterTagWidth <= availableWidth;
21
+ };
22
+ const fittingTagIndex = tagWidths.findIndex((_, index) => {
23
+ const widthBeforeCurrentTag = tagWidths
24
+ .slice(0, index)
25
+ .reduce((sum, width, i) => sum + width + (i > 0 ? GAP_BETWEEN_TAGS : 0), 0);
26
+ return !canFitTagAtIndex(index, widthBeforeCurrentTag);
27
+ });
28
+ const visibleTagsCount = fittingTagIndex === -1 ? tagLabels.length : fittingTagIndex;
29
+ if (visibleTagsCount === 0) {
30
+ const counterWidthAlone = getTagWidth(`+${tagLabels.length}`, theme);
31
+ const remainingAfterCounter = availableWidth - counterWidthAlone;
32
+ return remainingAfterCounter < MIN_AVAILABLE_WIDTH ? 0 : 1;
33
+ }
34
+ return visibleTagsCount;
35
+ };
@@ -0,0 +1 @@
1
+ export { calculateVisibleTagsCount } from './calculateVisibleTagsCount';
@@ -0,0 +1 @@
1
+ export { calculateVisibleTagsCount } from './calculateVisibleTagsCount';
@@ -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: TagValue, keyId: string) => string;
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
- const key = option[keyId];
6
- return typeof key === 'number' ? key.toString() : key;
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,2 @@
1
+ import { type Theme } from '../../../theme/types';
2
+ export declare const getTagWidth: (label: string | number, theme: Theme, isCounter?: boolean) => number;
@@ -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 classes = useMemo(() => {
41
- return classNames(className, hideHelperText ? textFieldClassnames.hideHelperText : '');
42
- }, [className, hideHelperText]);
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: classes, ...props }));
51
+ }, onBlur: handleBlur, className: classnames, disabled: disabled, ...props }));
51
52
  });