@cloud-ru/ds-uikit-product-header 2.0.2 → 2.0.3-preview-1207a902.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/dist/cjs/components/MainMenu/helperComponents/MenuBottom/MenuBottom.js +1 -1
- package/dist/cjs/components/MainMenu/helperComponents/MenuMobile/MenuMobile.js +2 -1
- package/dist/cjs/components/MainMenu/helperComponents/ScrollWithAnimatedStickyPanel/ScrollWithAnimatedStickyPanel.js +18 -6
- package/dist/cjs/components/UserMenu/UserMenu.js +5 -4
- package/dist/cjs/components/UserMenu/hooks/useLogoutItem.d.ts +2 -2
- package/dist/cjs/components/UserMenu/hooks/useLogoutItem.js +12 -9
- package/dist/cjs/components/UserMenu/hooks/useUserMenuItems.js +3 -3
- package/dist/cjs/components/UserMenu/styles.module.css +9 -0
- package/dist/cjs/constants.d.ts +0 -1
- package/dist/cjs/constants.js +1 -3
- package/dist/cjs/style.css +9 -0
- package/dist/esm/components/MainMenu/helperComponents/MenuBottom/MenuBottom.js +2 -2
- package/dist/esm/components/MainMenu/helperComponents/MenuMobile/MenuMobile.js +3 -2
- package/dist/esm/components/MainMenu/helperComponents/ScrollWithAnimatedStickyPanel/ScrollWithAnimatedStickyPanel.js +18 -6
- package/dist/esm/components/UserMenu/UserMenu.js +8 -7
- package/dist/esm/components/UserMenu/hooks/useLogoutItem.d.ts +2 -2
- package/dist/esm/components/UserMenu/hooks/useLogoutItem.js +9 -9
- package/dist/esm/components/UserMenu/hooks/useUserMenuItems.js +3 -3
- package/dist/esm/components/UserMenu/styles.module.css +9 -0
- package/dist/esm/constants.d.ts +0 -1
- package/dist/esm/constants.js +0 -2
- package/dist/esm/style.css +9 -0
- package/dist/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/tsconfig.esm.tsbuildinfo +1 -1
- package/package.json +28 -28
- package/src/components/MainMenu/helperComponents/MenuBottom/MenuBottom.tsx +2 -2
- package/src/components/MainMenu/helperComponents/MenuMobile/MenuMobile.tsx +3 -2
- package/src/components/MainMenu/helperComponents/ScrollWithAnimatedStickyPanel/ScrollWithAnimatedStickyPanel.tsx +21 -10
- package/src/components/UserMenu/UserMenu.tsx +12 -7
- package/src/components/UserMenu/hooks/useLogoutItem.tsx +12 -12
- package/src/components/UserMenu/hooks/useUserMenuItems.ts +4 -4
- package/src/components/UserMenu/styles.module.scss +11 -0
- package/src/constants.ts +0 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloud-ru/ds-uikit-product-header",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.3-preview-1207a902.0",
|
|
4
4
|
"description": "Продуктовая шапка консоли — HeaderLayout, MainMenu, UserMenu, Logo, PathBreadcrumbs и PlatformLogo.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -45,33 +45,33 @@
|
|
|
45
45
|
"@dnd-kit/utilities": "^3.2.2",
|
|
46
46
|
"classnames": "^2.5.1",
|
|
47
47
|
"fuse.js": "^7.1.0",
|
|
48
|
-
"@cloud-ru/ds-
|
|
49
|
-
"@cloud-ru/ds-
|
|
50
|
-
"@cloud-ru/ds-avatar": "
|
|
51
|
-
"@cloud-ru/ds-breadcrumbs": "
|
|
52
|
-
"@cloud-ru/ds-button": "
|
|
53
|
-
"@cloud-ru/ds-
|
|
54
|
-
"@cloud-ru/ds-
|
|
55
|
-
"@cloud-ru/ds-
|
|
56
|
-
"@cloud-ru/ds-
|
|
57
|
-
"@cloud-ru/ds-info-block": "
|
|
58
|
-
"@cloud-ru/ds-
|
|
59
|
-
"@cloud-ru/ds-
|
|
60
|
-
"@cloud-ru/ds-
|
|
61
|
-
"@cloud-ru/ds-
|
|
62
|
-
"@cloud-ru/ds-
|
|
63
|
-
"@cloud-ru/ds-
|
|
64
|
-
"@cloud-ru/ds-scroll": "
|
|
65
|
-
"@cloud-ru/ds-
|
|
66
|
-
"@cloud-ru/ds-
|
|
67
|
-
"@cloud-ru/ds-
|
|
68
|
-
"@cloud-ru/ds-
|
|
69
|
-
"@cloud-ru/ds-
|
|
70
|
-
"@cloud-ru/ds-typography": "
|
|
71
|
-
"@cloud-ru/ds-uikit-product-switch-row": "
|
|
72
|
-
"@cloud-ru/ds-
|
|
73
|
-
"@cloud-ru/ds-
|
|
74
|
-
"@cloud-ru/ds-uikit-product-title-clickable": "
|
|
48
|
+
"@cloud-ru/ds-adaptive": "1.0.2",
|
|
49
|
+
"@cloud-ru/ds-accordion": "1.1.3",
|
|
50
|
+
"@cloud-ru/ds-avatar": "1.0.8",
|
|
51
|
+
"@cloud-ru/ds-breadcrumbs": "1.0.23-preview-1207a902.0",
|
|
52
|
+
"@cloud-ru/ds-button": "1.0.4",
|
|
53
|
+
"@cloud-ru/ds-card": "1.0.18-preview-1207a902.0",
|
|
54
|
+
"@cloud-ru/ds-drag-and-drop": "1.1.3",
|
|
55
|
+
"@cloud-ru/ds-divider": "1.0.2",
|
|
56
|
+
"@cloud-ru/ds-icons": "1.3.0",
|
|
57
|
+
"@cloud-ru/ds-info-block": "1.0.3",
|
|
58
|
+
"@cloud-ru/ds-list": "2.2.6-preview-1207a902.0",
|
|
59
|
+
"@cloud-ru/ds-locale": "1.0.0",
|
|
60
|
+
"@cloud-ru/ds-modal": "1.1.7-preview-1207a902.0",
|
|
61
|
+
"@cloud-ru/ds-portal-context": "1.0.2",
|
|
62
|
+
"@cloud-ru/ds-promo-tag": "1.0.3",
|
|
63
|
+
"@cloud-ru/ds-search": "1.0.11",
|
|
64
|
+
"@cloud-ru/ds-scroll": "1.0.5",
|
|
65
|
+
"@cloud-ru/ds-segment-control": "1.0.10",
|
|
66
|
+
"@cloud-ru/ds-drawer": "1.2.6-preview-1207a902.0",
|
|
67
|
+
"@cloud-ru/ds-skeleton": "1.0.2",
|
|
68
|
+
"@cloud-ru/ds-theme": "2.0.0",
|
|
69
|
+
"@cloud-ru/ds-tooltip": "1.0.8",
|
|
70
|
+
"@cloud-ru/ds-typography": "1.0.0",
|
|
71
|
+
"@cloud-ru/ds-uikit-product-switch-row": "1.0.11",
|
|
72
|
+
"@cloud-ru/ds-utils": "1.2.0",
|
|
73
|
+
"@cloud-ru/ds-uikit-product-card-predefined": "4.0.3-preview-1207a902.0",
|
|
74
|
+
"@cloud-ru/ds-uikit-product-title-clickable": "1.0.13"
|
|
75
75
|
},
|
|
76
76
|
"publishConfig": {
|
|
77
77
|
"access": "public"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Divider } from '@cloud-ru/ds-divider';
|
|
2
|
-
import {
|
|
2
|
+
import { CardNavigation } from '@cloud-ru/ds-uikit-product-card-predefined';
|
|
3
3
|
import { Fragment, ReactNode } from 'react';
|
|
4
4
|
|
|
5
5
|
import { TEST_IDS } from '../../../../constants';
|
|
@@ -23,7 +23,7 @@ export function MenuBottom({ settingItems, leftBottom }: MenuBottomProps) {
|
|
|
23
23
|
<Fragment key={item.id}>
|
|
24
24
|
{item.divider === 'before' && <Divider orientation='horizontal' className={styles.bottomDivider} />}
|
|
25
25
|
|
|
26
|
-
<
|
|
26
|
+
<CardNavigation
|
|
27
27
|
{...(item.href ? { href: item.href, as: 'a' } : { as: 'button', type: 'button' })}
|
|
28
28
|
title={item.label}
|
|
29
29
|
icon={getLinkEmblem(item)}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Divider } from '@cloud-ru/ds-divider';
|
|
2
|
+
import { SNAP_POINTS_PRESET } from '@cloud-ru/ds-list';
|
|
2
3
|
import { useCallback, useMemo } from 'react';
|
|
3
4
|
|
|
4
|
-
import {
|
|
5
|
+
import { TEST_IDS } from '../../../../constants';
|
|
5
6
|
import { MobileDrawerCustom } from '../../../../mobileOverlays';
|
|
6
7
|
import { MainMenuDndContext } from '../../hooks/useMainMenuDnd';
|
|
7
8
|
import { useMenuItems } from '../../hooks/useMenuItems';
|
|
@@ -67,7 +68,7 @@ export function MenuMobile({
|
|
|
67
68
|
swipeEnabled={false}
|
|
68
69
|
data-test-id={TEST_IDS.mainMenu.drawerMobile}
|
|
69
70
|
closeOnPopstate
|
|
70
|
-
snapPoints={
|
|
71
|
+
snapPoints={SNAP_POINTS_PRESET.full}
|
|
71
72
|
disableMotions={true}
|
|
72
73
|
>
|
|
73
74
|
<ScrollWithAnimatedStickyPanel
|
|
@@ -7,6 +7,11 @@ type ScrollWithAnimatedStickyPanelProps = PropsWithChildren<{
|
|
|
7
7
|
panel: ReactNode;
|
|
8
8
|
}>;
|
|
9
9
|
|
|
10
|
+
// Упругая прокрутка у верхней границы (touch-скролл на мобильных не "упирается" жёстко в 0 —
|
|
11
|
+
// контент можно немного "оттянуть" дальше) даёт scrollTop, не совпадающий с реальным положением
|
|
12
|
+
// контента в этот момент. Диапазон запаса — единицы пикселей; двух хватает с большим запасом.
|
|
13
|
+
const TOP_OVERSCROLL_EPSILON_PX = 2;
|
|
14
|
+
|
|
10
15
|
export function ScrollWithAnimatedStickyPanel({ panel, children }: ScrollWithAnimatedStickyPanelProps) {
|
|
11
16
|
const [positions, setPositions] = useState({ panelTopShift: 0, containerScroll: 0 });
|
|
12
17
|
const [panelHeight, setPanelHeight] = useState(0);
|
|
@@ -23,6 +28,14 @@ export function ScrollWithAnimatedStickyPanel({ panel, children }: ScrollWithAni
|
|
|
23
28
|
|
|
24
29
|
setPanelHeight(panelHeight);
|
|
25
30
|
|
|
31
|
+
// У верхней границы панель всегда полностью видна — не доверяем накопленному diff. Иначе
|
|
32
|
+
// "лишний" ход упругой прокрутки у самого верха читается как скролл вниз и на возврате к
|
|
33
|
+
// началу списка панель может остаться скрытой, хотя пользователь как раз скроллит наверх.
|
|
34
|
+
if (target.scrollTop <= TOP_OVERSCROLL_EPSILON_PX) {
|
|
35
|
+
setPositions({ panelTopShift: 0, containerScroll: target.scrollTop });
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
26
39
|
setPositions(prev => {
|
|
27
40
|
const diff = prev.containerScroll - target.scrollTop;
|
|
28
41
|
|
|
@@ -33,21 +46,19 @@ export function ScrollWithAnimatedStickyPanel({ panel, children }: ScrollWithAni
|
|
|
33
46
|
});
|
|
34
47
|
}, []);
|
|
35
48
|
|
|
49
|
+
const setPanelRef = useCallback((element: HTMLDivElement | null) => {
|
|
50
|
+
if (element) {
|
|
51
|
+
setPanelHeight(element.offsetHeight);
|
|
52
|
+
panelRef.current = element;
|
|
53
|
+
}
|
|
54
|
+
}, []);
|
|
55
|
+
|
|
36
56
|
return (
|
|
37
57
|
<div className={styles.container} style={{ '--snack-autohide-panel-height': `${panelHeight}px` }}>
|
|
38
58
|
<Scroll barHideStrategy='never' overflow={{ x: 'hidden' }} onScroll={handleScroll}>
|
|
39
59
|
{children}
|
|
40
60
|
</Scroll>
|
|
41
|
-
<div
|
|
42
|
-
className={styles.panel}
|
|
43
|
-
ref={element => {
|
|
44
|
-
if (element) {
|
|
45
|
-
setPanelHeight(element.offsetHeight);
|
|
46
|
-
panelRef.current = element;
|
|
47
|
-
}
|
|
48
|
-
}}
|
|
49
|
-
style={{ top: positions.panelTopShift }}
|
|
50
|
-
>
|
|
61
|
+
<div className={styles.panel} ref={setPanelRef} style={{ top: positions.panelTopShift }}>
|
|
51
62
|
{panel}
|
|
52
63
|
</div>
|
|
53
64
|
</div>
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Avatar } from '@cloud-ru/ds-avatar';
|
|
2
|
-
import { BaseItemProps, Droplist, DroplistProps } from '@cloud-ru/ds-list';
|
|
2
|
+
import { BaseItemProps, Droplist, DroplistProps, SNAP_POINTS_PRESET } from '@cloud-ru/ds-list';
|
|
3
3
|
import { useValueControl } from '@cloud-ru/ds-utils';
|
|
4
4
|
import cn from 'classnames';
|
|
5
|
-
import { useMemo } from 'react';
|
|
5
|
+
import { useCallback, useMemo } from 'react';
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { TEST_IDS } from '../../constants';
|
|
8
8
|
import { useDesktopComfortClassName } from '../../hooks/useDesktopComfortClassName';
|
|
9
9
|
import { useMobileLayout } from '../../hooks/useMobileLayout';
|
|
10
10
|
import { headerLocale } from '../../locale';
|
|
@@ -77,6 +77,10 @@ export function UserMenu({
|
|
|
77
77
|
|
|
78
78
|
const { fullName = '', inviteCount } = profile;
|
|
79
79
|
|
|
80
|
+
const handleClose = useCallback(() => {
|
|
81
|
+
setOpen(false);
|
|
82
|
+
}, [setOpen]);
|
|
83
|
+
|
|
80
84
|
const {
|
|
81
85
|
pinTop,
|
|
82
86
|
items: menuItems,
|
|
@@ -89,9 +93,7 @@ export function UserMenu({
|
|
|
89
93
|
organizationItems,
|
|
90
94
|
bottomItems,
|
|
91
95
|
settingItems,
|
|
92
|
-
onClose:
|
|
93
|
-
setOpen(false);
|
|
94
|
-
},
|
|
96
|
+
onClose: handleClose,
|
|
95
97
|
onLogout,
|
|
96
98
|
});
|
|
97
99
|
|
|
@@ -136,7 +138,10 @@ export function UserMenu({
|
|
|
136
138
|
closeOnPopstate
|
|
137
139
|
data-test-id={TEST_IDS.userMenu.root}
|
|
138
140
|
label={t('user')}
|
|
139
|
-
snapPoints={
|
|
141
|
+
snapPoints={SNAP_POINTS_PRESET.full}
|
|
142
|
+
safeArea
|
|
143
|
+
withDividers={false}
|
|
144
|
+
triggerClassName={styles.userMenuDroplistTrigger}
|
|
140
145
|
>
|
|
141
146
|
{trigger}
|
|
142
147
|
</Droplist>
|
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
import { ExitSVG } from '@cloud-ru/ds-icons/interface/product';
|
|
2
|
-
import {
|
|
2
|
+
import { BaseItem } from '@cloud-ru/ds-list';
|
|
3
3
|
import { useMemo } from 'react';
|
|
4
4
|
|
|
5
5
|
import { headerLocale } from '../../../locale';
|
|
6
|
+
import styles from '../styles.module.scss';
|
|
6
7
|
|
|
7
|
-
export function useLogoutItem({ onLogout }: { onLogout?(): void }):
|
|
8
|
+
export function useLogoutItem({ onLogout }: { onLogout?(): void }): BaseItem {
|
|
8
9
|
const { t } = headerLocale.useTranslations();
|
|
9
10
|
|
|
10
|
-
return useMemo<
|
|
11
|
-
() =>
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
label: t('logout'),
|
|
16
|
-
},
|
|
17
|
-
onClick: onLogout,
|
|
18
|
-
'data-test-id': 'header__user-menu__logout',
|
|
11
|
+
return useMemo<BaseItem>(
|
|
12
|
+
() => ({
|
|
13
|
+
beforeContent: <ExitSVG />,
|
|
14
|
+
content: {
|
|
15
|
+
label: t('logout'),
|
|
19
16
|
},
|
|
20
|
-
|
|
17
|
+
className: styles.logoutItem,
|
|
18
|
+
onClick: onLogout,
|
|
19
|
+
'data-test-id': 'header__user-menu__logout',
|
|
20
|
+
}),
|
|
21
21
|
[onLogout, t],
|
|
22
22
|
);
|
|
23
23
|
}
|
|
@@ -79,12 +79,12 @@ export function useUserMenuItems({
|
|
|
79
79
|
|
|
80
80
|
let pinBottom = bottomItems.concat(logoutItem);
|
|
81
81
|
|
|
82
|
-
if (isMobile && Boolean(settingItems?.length)) {
|
|
83
|
-
pinBottom = pinBottom.concat([DIVIDER_ITEM, ...settingItems]);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
82
|
// В шторке прокручивается всё меню, закреплять части незачем; разделитель над организациями добавляем сами
|
|
87
83
|
if (isMobile) {
|
|
84
|
+
if (settingItems?.length) {
|
|
85
|
+
pinBottom = [...bottomItems, ...settingItems, DIVIDER_ITEM, logoutItem];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
88
|
return {
|
|
89
89
|
pinTop: [],
|
|
90
90
|
items: withClose([...pinTop, DIVIDER_ITEM, ...organizationItems, ...pinBottom]),
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
@use '@cloud-ru/ds-figma-variables/build/scss/styles/styles.module' as base;
|
|
2
2
|
|
|
3
|
+
.userMenuDroplistTrigger {
|
|
4
|
+
display: inline-flex;
|
|
5
|
+
}
|
|
6
|
+
|
|
3
7
|
.userMenuDroplist {
|
|
4
8
|
width: 256px; // нет токена ширины дропдауна
|
|
5
9
|
}
|
|
@@ -8,3 +12,10 @@
|
|
|
8
12
|
.profileSettingsIcon {
|
|
9
13
|
color: base.$sn-theme-color-neutral-text;
|
|
10
14
|
}
|
|
15
|
+
|
|
16
|
+
.logoutItem {
|
|
17
|
+
span,
|
|
18
|
+
svg {
|
|
19
|
+
color: base.$sn-theme-color-red-text;
|
|
20
|
+
}
|
|
21
|
+
}
|