@vkontakte/vkui 4.38.0 → 4.38.2

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 (92) hide show
  1. package/.cache/.eslintcache +1 -1
  2. package/.cache/.stylelintcache +1 -1
  3. package/.cache/.tsbuildinfo +19 -10
  4. package/.cache/ts/src/components/BaseGallery/BaseGallery.d.ts +1 -1
  5. package/.cache/ts/src/components/ContentCard/ContentCard.d.ts +1 -1
  6. package/.cache/ts/src/hooks/useId.d.ts +1 -0
  7. package/dist/cjs/components/BaseGallery/BaseGallery.d.ts +1 -1
  8. package/dist/cjs/components/BaseGallery/BaseGallery.js +4 -3
  9. package/dist/cjs/components/BaseGallery/BaseGallery.js.map +1 -1
  10. package/dist/cjs/components/ContentCard/ContentCard.d.ts +1 -1
  11. package/dist/cjs/components/ContentCard/ContentCard.js +7 -3
  12. package/dist/cjs/components/ContentCard/ContentCard.js.map +1 -1
  13. package/dist/cjs/components/DropdownIcon/DropdownIcon.js +2 -1
  14. package/dist/cjs/components/DropdownIcon/DropdownIcon.js.map +1 -1
  15. package/dist/cjs/components/InfoRow/InfoRow.js +3 -1
  16. package/dist/cjs/components/InfoRow/InfoRow.js.map +1 -1
  17. package/dist/cjs/components/MiniInfoCell/MiniInfoCell.js +14 -8
  18. package/dist/cjs/components/MiniInfoCell/MiniInfoCell.js.map +1 -1
  19. package/dist/cjs/components/UsersStack/UsersStack.js +29 -16
  20. package/dist/cjs/components/UsersStack/UsersStack.js.map +1 -1
  21. package/dist/cjs/hooks/useId.d.ts +1 -0
  22. package/dist/cjs/hooks/useId.js +33 -0
  23. package/dist/cjs/hooks/useId.js.map +1 -0
  24. package/dist/components/BaseGallery/BaseGallery.d.ts +1 -1
  25. package/dist/components/BaseGallery/BaseGallery.js +4 -3
  26. package/dist/components/BaseGallery/BaseGallery.js.map +1 -1
  27. package/dist/components/ContentCard/ContentCard.d.ts +1 -1
  28. package/dist/components/ContentCard/ContentCard.js +7 -3
  29. package/dist/components/ContentCard/ContentCard.js.map +1 -1
  30. package/dist/components/DropdownIcon/DropdownIcon.js +2 -1
  31. package/dist/components/DropdownIcon/DropdownIcon.js.map +1 -1
  32. package/dist/components/InfoRow/InfoRow.js +3 -1
  33. package/dist/components/InfoRow/InfoRow.js.map +1 -1
  34. package/dist/components/MiniInfoCell/MiniInfoCell.js +11 -8
  35. package/dist/components/MiniInfoCell/MiniInfoCell.js.map +1 -1
  36. package/dist/components/UsersStack/UsersStack.js +28 -16
  37. package/dist/components/UsersStack/UsersStack.js.map +1 -1
  38. package/dist/components.css +12 -12
  39. package/dist/components.css.map +1 -1
  40. package/dist/cssm/components/BaseGallery/BaseGallery.css +1 -1
  41. package/dist/cssm/components/BaseGallery/BaseGallery.d.ts +1 -1
  42. package/dist/cssm/components/BaseGallery/BaseGallery.js +4 -3
  43. package/dist/cssm/components/BaseGallery/BaseGallery.js.map +1 -1
  44. package/dist/cssm/components/CardGrid/CardGrid.css +1 -1
  45. package/dist/cssm/components/ContentCard/ContentCard.d.ts +1 -1
  46. package/dist/cssm/components/ContentCard/ContentCard.js +7 -3
  47. package/dist/cssm/components/ContentCard/ContentCard.js.map +1 -1
  48. package/dist/cssm/components/Counter/Counter.css +3 -3
  49. package/dist/cssm/components/DropdownIcon/DropdownIcon.js +2 -1
  50. package/dist/cssm/components/DropdownIcon/DropdownIcon.js.map +1 -1
  51. package/dist/cssm/components/FixedLayout/FixedLayout.css +1 -1
  52. package/dist/cssm/components/FormField/FormField.css +1 -1
  53. package/dist/cssm/components/FormLayoutGroup/FormLayoutGroup.css +1 -1
  54. package/dist/cssm/components/InfoRow/InfoRow.js +3 -1
  55. package/dist/cssm/components/InfoRow/InfoRow.js.map +1 -1
  56. package/dist/cssm/components/Link/Link.css +1 -1
  57. package/dist/cssm/components/MiniInfoCell/MiniInfoCell.js +11 -8
  58. package/dist/cssm/components/MiniInfoCell/MiniInfoCell.js.map +1 -1
  59. package/dist/cssm/components/Removable/Removable.css +1 -1
  60. package/dist/cssm/components/Tappable/Tappable.css +1 -1
  61. package/dist/cssm/components/UsersStack/UsersStack.css +2 -2
  62. package/dist/cssm/components/UsersStack/UsersStack.js +28 -16
  63. package/dist/cssm/components/UsersStack/UsersStack.js.map +1 -1
  64. package/dist/cssm/hooks/useId.d.ts +1 -0
  65. package/dist/cssm/hooks/useId.js +19 -0
  66. package/dist/cssm/hooks/useId.js.map +1 -0
  67. package/dist/cssm/styles/components.css +12 -12
  68. package/dist/hooks/useId.d.ts +1 -0
  69. package/dist/hooks/useId.js +19 -0
  70. package/dist/hooks/useId.js.map +1 -0
  71. package/dist/vkui.css +12 -12
  72. package/dist/vkui.css.map +1 -1
  73. package/package.json +1 -1
  74. package/src/components/BaseGallery/BaseGallery.css +4 -1
  75. package/src/components/BaseGallery/BaseGallery.tsx +5 -2
  76. package/src/components/CardGrid/CardGrid.css +7 -7
  77. package/src/components/ContentCard/ContentCard.tsx +4 -2
  78. package/src/components/Counter/Counter.css +10 -5
  79. package/src/components/DropdownIcon/DropdownIcon.tsx +3 -1
  80. package/src/components/FixedLayout/FixedLayout.css +8 -0
  81. package/src/components/FormField/FormField.css +4 -0
  82. package/src/components/FormLayoutGroup/FormLayoutGroup.css +2 -1
  83. package/src/components/InfoRow/InfoRow.tsx +1 -1
  84. package/src/components/Link/Link.css +2 -1
  85. package/src/components/MiniInfoCell/MiniInfoCell.tsx +23 -14
  86. package/src/components/Removable/Removable.css +4 -0
  87. package/src/components/Root/Readme.md +1 -1
  88. package/src/components/SimpleCell/Readme.md +2 -2
  89. package/src/components/Tappable/Tappable.css +1 -0
  90. package/src/components/UsersStack/UsersStack.css +13 -51
  91. package/src/components/UsersStack/UsersStack.tsx +48 -43
  92. package/src/hooks/useId.ts +18 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vkontakte/vkui",
3
- "version": "4.38.0",
3
+ "version": "4.38.2",
4
4
  "main": "dist/cjs/index.js",
5
5
  "module": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
@@ -19,10 +19,13 @@
19
19
  width: 100%;
20
20
  height: 100%;
21
21
  min-height: 100px;
22
- cursor: grab;
23
22
  align-items: stretch;
24
23
  }
25
24
 
25
+ .Gallery--draggable .Gallery__layer {
26
+ cursor: grab;
27
+ }
28
+
26
29
  .Gallery__layer:empty {
27
30
  min-height: 0;
28
31
  }
@@ -42,7 +42,7 @@ export const BaseGallery = ({
42
42
  children,
43
43
  slideWidth = "100%",
44
44
  slideIndex = 0,
45
- isDraggable = true,
45
+ isDraggable: isDraggableProp = true,
46
46
  onDragStart,
47
47
  onDragEnd,
48
48
  onChange,
@@ -256,7 +256,7 @@ export const BaseGallery = ({
256
256
  };
257
257
 
258
258
  const onMoveX = (e: TouchEvent) => {
259
- if (isDraggable && !layoutState.current.isFullyVisible) {
259
+ if (isDraggableProp && !layoutState.current.isFullyVisible) {
260
260
  e.originalEvent.preventDefault();
261
261
 
262
262
  if (e.isSlideX) {
@@ -331,6 +331,8 @@ export const BaseGallery = ({
331
331
  // otherwise we need to check current slide index (align = right or align = center)
332
332
  (align !== "left" && slideIndex < layoutState.current.slides.length - 1));
333
333
 
334
+ const isDraggable = isDraggableProp && !layoutState.current.isFullyVisible;
335
+
334
336
  return (
335
337
  <div
336
338
  {...restProps}
@@ -338,6 +340,7 @@ export const BaseGallery = ({
338
340
  "Gallery",
339
341
  `Gallery--${align}`,
340
342
  shiftState.dragging && "Gallery--dragging",
343
+ isDraggable && "Gallery--draggable",
341
344
  slideWidth === "custom" && "Gallery--custom-width"
342
345
  )}
343
346
  ref={rootRef}
@@ -24,7 +24,7 @@
24
24
  }
25
25
 
26
26
  .CardGrid--m .Card {
27
- width: calc((100% - 8px) / 2);
27
+ width: calc(50% - (var(--vkui--size_cardgrid_padding--regular) / 2));
28
28
  }
29
29
 
30
30
  .CardGrid--m .Card:nth-child(n + 3) {
@@ -36,7 +36,7 @@
36
36
  }
37
37
 
38
38
  .CardGrid--s .Card {
39
- width: calc((100% - 2 * 8px) / 3);
39
+ width: calc((100% - 2 * var(--vkui--size_cardgrid_padding--regular)) / 3);
40
40
  }
41
41
 
42
42
  .CardGrid--s .Card:nth-child(n + 4) {
@@ -53,7 +53,7 @@
53
53
  }
54
54
 
55
55
  .CardGrid + .CardGrid {
56
- margin-top: 16px;
56
+ margin-top: calc(var(--vkui--size_cardgrid_padding_vertical--regular) * 2);
57
57
  }
58
58
 
59
59
  /**
@@ -61,14 +61,14 @@
61
61
  */
62
62
 
63
63
  .Group--card .CardGrid {
64
- padding-left: 8px;
65
- padding-right: 8px;
64
+ padding-left: var(--vkui--size_base_padding_horizontal--regular);
65
+ padding-right: var(--vkui--size_base_padding_horizontal--regular);
66
66
  }
67
67
 
68
68
  .Group .CardGrid:first-child {
69
- margin-top: 8px;
69
+ margin-top: var(--vkui--size_cardgrid_padding_vertical--regular);
70
70
  }
71
71
 
72
72
  .Group .CardGrid:last-child {
73
- margin-bottom: 8px;
73
+ margin-bottom: var(--vkui--size_cardgrid_padding_vertical--regular);
74
74
  }
@@ -75,6 +75,8 @@ export const ContentCard = ({
75
75
  referrerPolicy,
76
76
  sizes,
77
77
  useMap,
78
+ hasHover = false,
79
+ hasActive = false,
78
80
  ...restProps
79
81
  }: ContentCardProps) => {
80
82
  const source = image || src;
@@ -97,8 +99,8 @@ export const ContentCard = ({
97
99
  <Tappable
98
100
  {...restProps}
99
101
  disabled={restProps.disabled || (!restProps.onClick && !restProps.href)}
100
- hasHover={false}
101
- hasActive={false}
102
+ hasHover={hasHover}
103
+ hasActive={hasActive}
102
104
  vkuiClass="ContentCard__tappable"
103
105
  >
104
106
  {(source || srcSet) && (
@@ -58,9 +58,7 @@
58
58
  * CMP:
59
59
  * Button
60
60
  */
61
- .Button--lvl-primary.Button--clr-accent .Counter,
62
- .Button--lvl-secondary.Button--clr-neutral .Counter,
63
- .Button--lvl-tertiary.Button--clr-neutral .Counter {
61
+ .Button--lvl-primary.Button--clr-accent .Counter {
64
62
  background-color: var(
65
63
  --button_primary_foreground,
66
64
  var(--vkui--color_background_contrast)
@@ -125,9 +123,16 @@
125
123
  .Button--lvl-primary.Button--clr-neutral .Counter {
126
124
  background-color: var(
127
125
  --media_overlay_button_background,
128
- var(--vkui--color_background_contrast)
126
+ var(--vkui--color_background_content)
129
127
  );
130
- color: var(--text_primary, var(--vkui--color_text_primary));
128
+ color: var(--vkui--color_text_primary_invariably);
129
+ }
130
+
131
+ .Button--lvl-secondary.Button--clr-neutral .Counter,
132
+ .Button--lvl-tertiary.Button--clr-neutral .Counter,
133
+ .Button--lvl-outline.Button--clr-neutral .Counter {
134
+ background-color: var(--accent, var(--vkui--color_background_accent));
135
+ color: var(--white, var(--vkui--color_text_contrast));
131
136
  }
132
137
 
133
138
  .Button--lvl-primary.Button--clr-overlay .Counter {
@@ -26,5 +26,7 @@ export const DropdownIcon = ({
26
26
  Icon = sizeY === SizeType.COMPACT ? Icon20ChevronUp : Icon24ChevronUp;
27
27
  }
28
28
 
29
- return <Icon vkuiClass={classNames("DropdownIcon")} {...restProps} />;
29
+ return (
30
+ <Icon vkuiClass={classNames("DropdownIcon")} aria-hidden {...restProps} />
31
+ );
30
32
  };
@@ -74,3 +74,11 @@
74
74
  ) + var(--safe-area-inset-top)
75
75
  );
76
76
  }
77
+
78
+ /**
79
+ * CMP:
80
+ * PanelHeaderContext
81
+ */
82
+ .FixedLayout.PanelHeaderContext {
83
+ z-index: 4;
84
+ }
@@ -147,6 +147,10 @@
147
147
  border-top-right-radius: 0;
148
148
  }
149
149
 
150
+ .Select .FormField__after {
151
+ pointer-events: none;
152
+ }
153
+
150
154
  /**
151
155
  * CMP:
152
156
  * CalendarHeader
@@ -54,6 +54,7 @@
54
54
  flex: 1;
55
55
  }
56
56
 
57
- .FormLayoutGroup--segmented > *:not(:first-child) {
57
+ .FormLayoutGroup--segmented
58
+ > *:not(:first-child):not(.FormLayoutGroup__offset) {
58
59
  margin-left: calc(-1 * var(--thin-border));
59
60
  }
@@ -12,7 +12,7 @@ export interface InfoRowProps extends React.HTMLAttributes<HTMLDivElement> {
12
12
  * @see https://vkcom.github.io/VKUI/#/InfoRow
13
13
  */
14
14
  export const InfoRow = ({ header, children, ...restProps }: InfoRowProps) => (
15
- <Headline {...restProps} vkuiClass="InfoRow" weight="3">
15
+ <Headline Component="span" {...restProps} vkuiClass="InfoRow" weight="3">
16
16
  {hasReactNode(header) && (
17
17
  <Subhead Component="span" vkuiClass="InfoRow__header">
18
18
  {header}
@@ -11,7 +11,8 @@
11
11
  border-radius: 0;
12
12
  }
13
13
 
14
- @media (hover: hover) {
14
+ /* See https://www.ctrl.blog/entry/css-media-hover-samsung.html */
15
+ @media (hover: hover) and (pointer: fine) {
15
16
  .Link:hover {
16
17
  text-decoration: underline;
17
18
  }
@@ -59,21 +59,15 @@ export const MiniInfoCell = ({
59
59
  children,
60
60
  ...restProps
61
61
  }: MiniInfoCellProps) => {
62
- const isClickable = !!restProps.onClick;
62
+ const cellClasses = classNames(
63
+ "MiniInfoCell",
64
+ mode !== "base" && `MiniInfoCell--md-${mode}`,
65
+ textWrap !== "nowrap" && `MiniInfoCell--wr-${textWrap}`,
66
+ `MiniInfoCell--lvl-${textLevel}`
67
+ );
63
68
 
64
- return (
65
- <Tappable
66
- Component="div"
67
- disabled={!isClickable}
68
- role={isClickable ? "button" : undefined}
69
- {...restProps}
70
- vkuiClass={classNames(
71
- "MiniInfoCell",
72
- mode !== "base" && `MiniInfoCell--md-${mode}`,
73
- textWrap !== "nowrap" && `MiniInfoCell--wr-${textWrap}`,
74
- `MiniInfoCell--lvl-${textLevel}`
75
- )}
76
- >
69
+ const cellContent = (
70
+ <React.Fragment>
77
71
  <span vkuiClass="MiniInfoCell__icon">{before}</span>
78
72
  <Paragraph
79
73
  vkuiClass="MiniInfoCell__content"
@@ -84,6 +78,21 @@ export const MiniInfoCell = ({
84
78
  {hasReactNode(after) && (
85
79
  <span vkuiClass="MiniInfoCell__after">{after}</span>
86
80
  )}
81
+ </React.Fragment>
82
+ );
83
+
84
+ return restProps.onClick ? (
85
+ <Tappable
86
+ Component="div"
87
+ role="button"
88
+ {...restProps}
89
+ vkuiClass={cellClasses}
90
+ >
91
+ {cellContent}
87
92
  </Tappable>
93
+ ) : (
94
+ <div {...restProps} vkuiClass={cellClasses}>
95
+ {cellContent}
96
+ </div>
88
97
  );
89
98
  };
@@ -103,6 +103,10 @@
103
103
  align-items: flex-start;
104
104
  }
105
105
 
106
+ .Removable__offset {
107
+ display: none;
108
+ }
109
+
106
110
  .FormItem--withTop .FormItem__removable ~ .Removable__offset,
107
111
  .FormLayoutGroup--removable .FormItem--withTop ~ .Removable__offset {
108
112
  order: -1;
@@ -1,4 +1,4 @@
1
- Используется для создания модальных окон. Содержимое `Root` – это коллекция `View`. У каждой `View` должен быть `id`.
1
+ Содержимое `Root` – это коллекция `View`. У каждой `View` должен быть `id`.
2
2
  Свойство `activeView` определяет, какая `View` сейчас активна.
3
3
 
4
4
  При смене значения свойства `activeView` происходит плавный переход от одной `View` к другой.
@@ -32,10 +32,10 @@ const Example = () => {
32
32
  </Group>
33
33
  <Group>
34
34
  <Header mode="secondary">Настройки</Header>
35
- <SimpleCell disabled after={<Switch defaultChecked />}>
35
+ <SimpleCell Component="label" after={<Switch defaultChecked />}>
36
36
  Сжимать фотографии
37
37
  </SimpleCell>
38
- <SimpleCell disabled after={<Switch />}>
38
+ <SimpleCell Component="label" after={<Switch />}>
39
39
  Сжимать видео
40
40
  </SimpleCell>
41
41
  </Group>
@@ -13,6 +13,7 @@
13
13
  .Tappable[disabled],
14
14
  .Tappable[aria-disabled="true"] {
15
15
  cursor: default;
16
+ pointer-events: none;
16
17
  }
17
18
 
18
19
  .Tappable--focus-visible {
@@ -4,10 +4,23 @@
4
4
  color: var(--text_secondary, var(--vkui--color_text_secondary));
5
5
  }
6
6
 
7
+ .UsersStack--l-vertical {
8
+ flex-direction: column;
9
+ justify-content: center;
10
+ }
11
+
7
12
  .UsersStack__photos {
8
13
  display: flex;
9
14
  }
10
15
 
16
+ .UsersStack--l-horizontal .UsersStack__photos {
17
+ margin-right: 8px;
18
+ }
19
+
20
+ .UsersStack--l-vertical .UsersStack__photos {
21
+ margin-bottom: 8px;
22
+ }
23
+
11
24
  .UsersStack__fill {
12
25
  fill: var(
13
26
  --placeholder_icon_background,
@@ -49,18 +62,9 @@
49
62
  .UsersStack__text {
50
63
  min-width: 0;
51
64
  flex: 1;
52
- margin: 0 0 0 8px;
53
- }
54
-
55
- /* Vertical layout */
56
-
57
- .UsersStack--l-vertical {
58
- flex-direction: column;
59
- justify-content: center;
60
65
  }
61
66
 
62
67
  .UsersStack--l-vertical .UsersStack__text {
63
- margin: 8px 0 0;
64
68
  text-align: center;
65
69
  }
66
70
 
@@ -71,45 +75,3 @@
71
75
  .ModalCardBase .UsersStack {
72
76
  margin-top: 20px;
73
77
  }
74
-
75
- .UsersStack__mask--16-left {
76
- clip-path: path(
77
- "M2,13.285A8 8 0 0 0 8 16A8 8 0 0 0 8 0A8 8 0 0 0 2 2.715A8 8 0 0 1 2,13.285"
78
- );
79
- }
80
-
81
- .UsersStack__mask--16-circle {
82
- clip-path: circle(8px);
83
- }
84
-
85
- .UsersStack__mask--24-left {
86
- clip-path: path(
87
- "M2,18.625A12 12 0 0 0 12 24A12 12 0 0 0 12 0A12 12 0 0 0 2 5.375A12 12 0 0 1 2,18.625"
88
- );
89
- }
90
-
91
- .UsersStack__mask--24-circle {
92
- clip-path: circle(12px);
93
- }
94
-
95
- .UsersStack__mask--24-right {
96
- clip-path: path(
97
- "M22,18.625A12 12 0 0 1 12 24A12 12 0 0 1 12 0A12 12 0 0 1 22 5.375A12 12 0 0 0 22,18.625"
98
- );
99
- }
100
-
101
- .UsersStack__mask--32-left {
102
- clip-path: path(
103
- "M2,23.75A16 16 0 0 0 16 32A16 16 0 0 0 16 0A16 16 0 0 0 2 8.25A16 16 0 0 1 2,23.75"
104
- );
105
- }
106
-
107
- .UsersStack__mask--32-circle {
108
- clip-path: circle(16px);
109
- }
110
-
111
- .UsersStack__mask--32-right {
112
- clip-path: path(
113
- "M30,23.75A16 16 0 0 1 16 32A16 16 0 0 1 16 0A16 16 0 0 1 30 8.25A16 16 0 0 0 30,23.75"
114
- );
115
- }
@@ -3,6 +3,7 @@ import { hasReactNode } from "../../lib/utils";
3
3
  import { classNames } from "../../lib/classNames";
4
4
  import { Footnote } from "../Typography/Footnote/Footnote";
5
5
  import { Caption } from "../Typography/Caption/Caption";
6
+ import { useId } from "../../hooks/useId";
6
7
  import "./UsersStack.css";
7
8
 
8
9
  export interface UsersStackProps extends React.HTMLAttributes<HTMLDivElement> {
@@ -102,6 +103,8 @@ export const UsersStack = ({
102
103
  children,
103
104
  ...restProps
104
105
  }: UsersStackProps) => {
106
+ const cmpId = useId();
107
+
105
108
  const canShowOthers = count > 0 && size !== "xs";
106
109
  const CounterTypography = size === "m" ? Footnote : Caption;
107
110
 
@@ -112,7 +115,45 @@ export const UsersStack = ({
112
115
  }[size];
113
116
  const directionClip = canShowOthers ? "right" : "left";
114
117
 
115
- const photosShown = photos.slice(0, visibleCount);
118
+ const photosElements = photos.slice(0, visibleCount).map((photo, i) => {
119
+ const direction = i === 0 && !canShowOthers ? "circle" : directionClip;
120
+
121
+ const id = `UsersStackDefs${cmpId}${i}`;
122
+ const hrefID = `#${id}`;
123
+ const maskID = `UsersStackMask${cmpId}${i}`;
124
+
125
+ return (
126
+ <svg
127
+ xmlns="http://www.w3.org/2000/svg"
128
+ vkuiClass="UsersStack__photo"
129
+ key={i}
130
+ aria-hidden
131
+ >
132
+ <defs>
133
+ <PathElement id={id} direction={direction} photoSize={photoSize} />
134
+ </defs>
135
+ <clipPath id={maskID}>
136
+ <use href={hrefID} />
137
+ </clipPath>
138
+ <g clipPath={`url(#${maskID})`}>
139
+ <use href={hrefID} vkuiClass="UsersStack__fill" />
140
+ <image href={photo} width={photoSize} height={photoSize} />
141
+ <use href={hrefID} fill="none" stroke="rgba(0, 0, 0, 0.08)" />
142
+ </g>
143
+ </svg>
144
+ );
145
+ });
146
+ const othersElement = canShowOthers ? (
147
+ <CounterTypography
148
+ caps
149
+ weight="1"
150
+ level="2" // TODO: remove only level in #2343
151
+ vkuiClass="UsersStack__photo UsersStack__photo--others"
152
+ aria-hidden
153
+ >
154
+ <span>+{count}</span>
155
+ </CounterTypography>
156
+ ) : null;
116
157
 
117
158
  return (
118
159
  <div
@@ -124,48 +165,12 @@ export const UsersStack = ({
124
165
  canShowOthers && "UsersStack--others"
125
166
  )}
126
167
  >
127
- <div vkuiClass="UsersStack__photos" role="presentation">
128
- {photosShown.map((photo, i) => {
129
- const direction =
130
- i === 0 && !canShowOthers ? "circle" : directionClip;
131
-
132
- return (
133
- <svg
134
- xmlns="http://www.w3.org/2000/svg"
135
- vkuiClass="UsersStack__photo"
136
- key={i}
137
- aria-hidden
138
- >
139
- <g vkuiClass={`UsersStack__mask--${photoSize}-${direction}`}>
140
- <PathElement
141
- direction={direction}
142
- photoSize={photoSize}
143
- vkuiClass="UsersStack__fill"
144
- />
145
- <image href={photo} width={photoSize} height={photoSize} />
146
- <PathElement
147
- direction={direction}
148
- photoSize={photoSize}
149
- fill="none"
150
- stroke="rgba(0, 0, 0, 0.08)"
151
- />
152
- </g>
153
- </svg>
154
- );
155
- })}
156
-
157
- {canShowOthers && (
158
- <CounterTypography
159
- caps
160
- weight="1"
161
- level="2" // TODO: remove only level in #2343
162
- vkuiClass="UsersStack__photo UsersStack__photo--others"
163
- aria-hidden
164
- >
165
- <span>+{count}</span>
166
- </CounterTypography>
167
- )}
168
- </div>
168
+ {(photosElements.length > 0 || othersElement) && (
169
+ <div vkuiClass="UsersStack__photos" role="presentation">
170
+ {photosElements}
171
+ {othersElement}
172
+ </div>
173
+ )}
169
174
  {hasReactNode(children) && (
170
175
  <Footnote vkuiClass="UsersStack__text">{children}</Footnote>
171
176
  )}
@@ -0,0 +1,18 @@
1
+ import * as React from "react";
2
+
3
+ // Workaround for https://github.com/webpack/webpack/issues/14814
4
+ // https://github.com/eps1lon/material-ui/blob/8d5f135b4d7a58253a99ab56dce4ac8de61f5dc1/packages/mui-utils/src/useId.ts#L21
5
+ const maybeReactUseId: undefined | (() => string) = (React as any)[
6
+ "useId".toString()
7
+ ];
8
+
9
+ let id = 0;
10
+
11
+ // TODO: Remove after React 18
12
+ function useIncrementingCounterID(): string {
13
+ const [state] = React.useState(() => id++);
14
+
15
+ return `:r${state}:`;
16
+ }
17
+
18
+ export const useId: () => string = maybeReactUseId ?? useIncrementingCounterID;