@skbkontur/side-menu 2.0.2 → 2.1.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.
- package/CHANGELOG.md +22 -0
- package/README.md +36 -0
- package/package.json +1 -1
- package/src/Navigation.d.ts +2 -1
- package/src/Navigation.js +4 -4
- package/src/SideMenu/SideMenu.d.ts +11 -0
- package/src/SideMenu/SideMenu.js +23 -12
- package/src/internal/BackButton.js +4 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,28 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [2.1.1](https://git.skbkontur.ru/ui/ui-parking/compare/@skbkontur/side-menu@2.1.0...@skbkontur/side-menu@2.1.1) (2024-08-08)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* **SideMenu:** use special attrs instead of data-tids attrs ([27db556](https://git.skbkontur.ru/ui/ui-parking/commits/27db5569a22014f8b18f4d6ce64844e7a61a722b))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# [2.1.0](https://git.skbkontur.ru/ui/ui-parking/compare/@skbkontur/side-menu@2.0.2...@skbkontur/side-menu@2.1.0) (2024-07-19)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Features
|
|
21
|
+
|
|
22
|
+
* **SideMenu:** add isPinned prop ([3e6e080](https://git.skbkontur.ru/ui/ui-parking/commits/3e6e080f37054e0e86ded3034a4975b0c99a2942))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
6
28
|
## [2.0.2](https://git.skbkontur.ru/ui/ui-parking/compare/@skbkontur/side-menu@2.0.0...@skbkontur/side-menu@2.0.2) (2024-07-18)
|
|
7
29
|
|
|
8
30
|
**Note:** Version bump only for package @skbkontur/side-menu
|
package/README.md
CHANGED
|
@@ -525,6 +525,42 @@ const [isOpen, setIsOpen] = React.useState(true);
|
|
|
525
525
|
</div>
|
|
526
526
|
```
|
|
527
527
|
|
|
528
|
+
#### Пример с использованием пропа `isPinned`
|
|
529
|
+
|
|
530
|
+
```jsx harmony
|
|
531
|
+
import { Kontur, Ofd } from '@skbkontur/logos';
|
|
532
|
+
import { SideMenu } from './index';
|
|
533
|
+
import { DocTextIcon24Regular } from '@skbkontur/icons/icons/DocTextIcon/DocTextIcon24Regular';
|
|
534
|
+
import { SettingsGearIcon24Regular } from '@skbkontur/icons/icons/SettingsGearIcon/SettingsGearIcon24Regular';
|
|
535
|
+
import { ThemeContext, ThemeFactory, Button } from '@skbkontur/react-ui';
|
|
536
|
+
|
|
537
|
+
const [isPinned, setIsPinned] = React.useState(localStorage.getItem('sideMenuIsPinned') === 'true');
|
|
538
|
+
|
|
539
|
+
React.useEffect(() => {
|
|
540
|
+
window.addEventListener('storage', () => {
|
|
541
|
+
setIsPinned(localStorage.getItem('sideMenuIsPinned') === 'true');
|
|
542
|
+
});
|
|
543
|
+
}, []);
|
|
544
|
+
|
|
545
|
+
<div style={{ height: '200px', position: 'relative', display: 'flex' }}>
|
|
546
|
+
<ThemeContext.Provider
|
|
547
|
+
value={ThemeFactory.create({ sideMenuWidth: '300px', sideMenuProductColor: '#64b419' })}>
|
|
548
|
+
<SideMenu isPinned={isPinned}
|
|
549
|
+
onPinnedValueChange={(isPinned) => {
|
|
550
|
+
localStorage.setItem('sideMenuIsPinned', String(isPinned));
|
|
551
|
+
}}>
|
|
552
|
+
<SideMenu.Header konturLogo={<Kontur />} productLogo={<Ofd />} />
|
|
553
|
+
<SideMenu.Body>
|
|
554
|
+
<SideMenu.Item icon={<DocTextIcon24Regular />} caption={'Документы к подписанию'} />
|
|
555
|
+
</SideMenu.Body>
|
|
556
|
+
<SideMenu.Footer>
|
|
557
|
+
<SideMenu.Item icon={<SettingsGearIcon24Regular />} caption={'Реквизиты и настройки'} />
|
|
558
|
+
</SideMenu.Footer>
|
|
559
|
+
</SideMenu>
|
|
560
|
+
</ThemeContext.Provider>
|
|
561
|
+
</div>
|
|
562
|
+
```
|
|
563
|
+
|
|
528
564
|
#### Переменные кастомизации (см. [ThemeContext](https://tech.skbkontur.ru/react-ui/#/Customization/ThemeContext))
|
|
529
565
|
|
|
530
566
|
```typescript
|
package/package.json
CHANGED
package/src/Navigation.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { RefObject } from 'react';
|
|
|
2
2
|
import { Tree, TreeNode } from './Tree';
|
|
3
3
|
export declare const navigationAttribute = "data-navigation-id";
|
|
4
4
|
export declare const navigationAttributeForSeparatedMenu = "data-parent-navigation-id";
|
|
5
|
+
export declare const navigationAttributeBackButton = "data-navigation-back-button";
|
|
5
6
|
export interface NavigableElement {
|
|
6
7
|
setIsActive: (value: boolean) => void;
|
|
7
8
|
setIsOpened: (value: boolean) => void;
|
|
@@ -34,7 +35,7 @@ export declare class MenuNavigation {
|
|
|
34
35
|
private readonly isOpened?;
|
|
35
36
|
private readonly isDesktop?;
|
|
36
37
|
private readonly isMobile?;
|
|
37
|
-
|
|
38
|
+
isCollapsable?: boolean;
|
|
38
39
|
constructor(options: MenuNavigationOptions);
|
|
39
40
|
updateNavigationTree(): void;
|
|
40
41
|
addValue(id: string, value: NavigableElement): void;
|
package/src/Navigation.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { __read, __spread } from "tslib";
|
|
2
|
-
import { SideMenuDataTids } from '../SideMenuDataTids';
|
|
3
2
|
import { Tree } from './Tree';
|
|
4
3
|
var MENU_ROOT_ID = 'menu-root-id';
|
|
5
4
|
export var navigationAttribute = 'data-navigation-id';
|
|
6
5
|
export var navigationAttributeForSeparatedMenu = 'data-parent-navigation-id';
|
|
6
|
+
export var navigationAttributeBackButton = 'data-navigation-back-button';
|
|
7
7
|
var MenuNavigation = /** @class */ (function () {
|
|
8
8
|
function MenuNavigation(options) {
|
|
9
9
|
this.navigationTree = null;
|
|
@@ -24,7 +24,7 @@ var MenuNavigation = /** @class */ (function () {
|
|
|
24
24
|
var _this = this;
|
|
25
25
|
var _a;
|
|
26
26
|
if ((_a = this.rootRef) === null || _a === void 0 ? void 0 : _a.current) {
|
|
27
|
-
var menuItems = Array.from(this.rootRef.current.querySelectorAll("[
|
|
27
|
+
var menuItems = Array.from(this.rootRef.current.querySelectorAll("[" + navigationAttribute + "]")).filter(function (item) { return !item.querySelector("[" + navigationAttributeBackButton + "]"); });
|
|
28
28
|
menuItems.forEach(function (menuItem) {
|
|
29
29
|
var _a, _b, _c;
|
|
30
30
|
var id = menuItem.getAttribute(navigationAttribute);
|
|
@@ -116,8 +116,8 @@ var MenuNavigation = /** @class */ (function () {
|
|
|
116
116
|
MenuNavigation.prototype.getParentId = function (menuItem) {
|
|
117
117
|
var _a, _b, _c;
|
|
118
118
|
var parentElement;
|
|
119
|
-
var clickableElementSelector = "[
|
|
120
|
-
var separatedMenuSelector = "[
|
|
119
|
+
var clickableElementSelector = "[" + navigationAttribute + "]";
|
|
120
|
+
var separatedMenuSelector = "[" + navigationAttributeForSeparatedMenu + "]";
|
|
121
121
|
parentElement = (_a = menuItem.parentElement) === null || _a === void 0 ? void 0 : _a.closest(clickableElementSelector);
|
|
122
122
|
if (!parentElement) {
|
|
123
123
|
var separatedMenu = menuItem.closest(separatedMenuSelector);
|
|
@@ -16,7 +16,18 @@ export declare type showScrollBarType = 'always' | 'scroll' | 'hover' | 'never';
|
|
|
16
16
|
export interface SideMenuProps extends CommonProps {
|
|
17
17
|
children?: React.ReactNode;
|
|
18
18
|
size?: 'small' | 'large';
|
|
19
|
+
/**
|
|
20
|
+
* Проп для отображения подменю в отдельной колонке
|
|
21
|
+
*/
|
|
19
22
|
isSeparatedMenu?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Проп для закрепленного состояния (работает только на широких экранах)
|
|
25
|
+
*/
|
|
26
|
+
isPinned?: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Коллбэк для закрепленного состояния (работает только на широких экранах)
|
|
29
|
+
*/
|
|
30
|
+
onPinnedValueChange?: (isPinned: boolean) => void;
|
|
20
31
|
/**
|
|
21
32
|
* @deprecated use disableCollapsing
|
|
22
33
|
*/
|
package/src/SideMenu/SideMenu.js
CHANGED
|
@@ -33,7 +33,7 @@ export var burgerTransitionDuration = (transitionDuration * 2) / 3;
|
|
|
33
33
|
var SideMenuInner = forwardRef(function (_a, ref) {
|
|
34
34
|
var _b, _c, _d, _e;
|
|
35
35
|
var _f, _g;
|
|
36
|
-
var children = _a.children, value = _a.value,
|
|
36
|
+
var children = _a.children, value = _a.value, activeItem = _a.activeItem, _h = _a.size, size = _h === void 0 ? 'small' : _h, _j = _a.isSeparatedMenu, isSeparatedMenu = _j === void 0 ? false : _j, className = _a.className, _k = _a.disableSwipe, disableSwipe = _k === void 0 ? false : _k, _l = _a.disableCollapsing, disableCollapsing = _l === void 0 ? false : _l, desktopMediaQuery = _a.desktopMediaQuery, narrowDesktopMediaQuery = _a.narrowDesktopMediaQuery, tabletMediaQuery = _a.tabletMediaQuery, mobileMediaQuery = _a.mobileMediaQuery, _m = _a.hideScrollBar, hideScrollBar = _m === void 0 ? undefined : _m, _o = _a.showScrollBar, showScrollBar = _o === void 0 ? 'hover' : _o, isOpen = _a.isOpen, isPinned = _a.isPinned, onValueChange = _a.onValueChange, onActiveItemChange = _a.onActiveItemChange, onOpen = _a.onOpen, onClose = _a.onClose, onPinnedValueChange = _a.onPinnedValueChange, rest = __rest(_a, ["children", "value", "activeItem", "size", "isSeparatedMenu", "className", "disableSwipe", "disableCollapsing", "desktopMediaQuery", "narrowDesktopMediaQuery", "tabletMediaQuery", "mobileMediaQuery", "hideScrollBar", "showScrollBar", "isOpen", "isPinned", "onValueChange", "onActiveItemChange", "onOpen", "onClose", "onPinnedValueChange"]);
|
|
37
37
|
var transitionTimer = useRef(null);
|
|
38
38
|
var sideMenuRef = useRef(null);
|
|
39
39
|
var contentWrapperRef = useRef(null);
|
|
@@ -55,7 +55,7 @@ var SideMenuInner = forwardRef(function (_a, ref) {
|
|
|
55
55
|
var isTabletOrMobile = isTablet || isMobile;
|
|
56
56
|
var isTouchScreen = isTouchDevice() || isMobile || isTablet;
|
|
57
57
|
var manual = isOpen !== undefined;
|
|
58
|
-
var _q = __read(useState(isDesktopQuery), 2), isOpened = _q[0], setIsOpened = _q[1];
|
|
58
|
+
var _q = __read(useState(isDesktopQuery && !isPinned), 2), isOpened = _q[0], setIsOpened = _q[1];
|
|
59
59
|
var _r = __read(useState(false), 2), isBeingTransitioned = _r[0], setIsBeingTransitioned = _r[1];
|
|
60
60
|
var _s = __read(useState(value !== null && value !== void 0 ? value : activeItem), 2), activeMenuItem = _s[0], setActiveMenuItem = _s[1];
|
|
61
61
|
var _t = __read(useState(false), 2), isSeparatedMenuShown = _t[0], setIsSeparatedMenuShown = _t[1];
|
|
@@ -64,7 +64,7 @@ var SideMenuInner = forwardRef(function (_a, ref) {
|
|
|
64
64
|
var _w = __read(useState(false), 2), hasScrollBar = _w[0], setHasScrollBar = _w[1];
|
|
65
65
|
var _x = __read(useState(0), 2), mousePositionX = _x[0], setMousePositionX = _x[1];
|
|
66
66
|
var _y = __read(useState(0), 2), headerHeight = _y[0], setHeaderHeight = _y[1];
|
|
67
|
-
var _z = __read(useState(isNarrowDesktop), 2), isCollapsable = _z[0], setIsCollapsable = _z[1];
|
|
67
|
+
var _z = __read(useState(isNarrowDesktop || (isDesktopQuery && isPinned)), 2), isCollapsable = _z[0], setIsCollapsable = _z[1];
|
|
68
68
|
var _0 = __read(useState(0), 2), leftPosition = _0[0], setLeftPosition = _0[1];
|
|
69
69
|
var _1 = __read(useState(false), 2), isHovered = _1[0], setIsHovered = _1[1];
|
|
70
70
|
var switchActiveMenuItem = function (id) {
|
|
@@ -107,6 +107,9 @@ var SideMenuInner = forwardRef(function (_a, ref) {
|
|
|
107
107
|
setHasScrollBar(scrollContainer.clientHeight < contentWrapper.scrollHeight);
|
|
108
108
|
}, 50);
|
|
109
109
|
}, [activeMenuItem, isOpened, isBeingTransitioned]);
|
|
110
|
+
useEffect(function () {
|
|
111
|
+
isDesktopQuery && setIsOpened(!isPinned);
|
|
112
|
+
}, [isPinned, isDesktopQuery]);
|
|
110
113
|
var handleIsOpened = function (newIsOpened, shouldSetState) {
|
|
111
114
|
if (newIsOpened === isOpened || !shouldSetState)
|
|
112
115
|
return;
|
|
@@ -119,7 +122,7 @@ var SideMenuInner = forwardRef(function (_a, ref) {
|
|
|
119
122
|
}
|
|
120
123
|
};
|
|
121
124
|
useEffect(function () {
|
|
122
|
-
if (isDesktopQuery) {
|
|
125
|
+
if (isDesktopQuery && !isPinned) {
|
|
123
126
|
setIsOpened(true);
|
|
124
127
|
setIsCollapsable(false);
|
|
125
128
|
}
|
|
@@ -127,7 +130,13 @@ var SideMenuInner = forwardRef(function (_a, ref) {
|
|
|
127
130
|
setIsOpened(false);
|
|
128
131
|
}
|
|
129
132
|
isNarrowDesktop && setIsCollapsable(true);
|
|
130
|
-
|
|
133
|
+
if (isDesktopQuery && isPinned) {
|
|
134
|
+
setIsCollapsable(true);
|
|
135
|
+
if (navigation.current) {
|
|
136
|
+
navigation.current.isCollapsable = true;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}, [isNarrowDesktop, isDesktopQuery, isTablet, isMobile, isPinned]);
|
|
131
140
|
useEffect(function () {
|
|
132
141
|
var _a;
|
|
133
142
|
!activeItem && ((_a = navigation.current) === null || _a === void 0 ? void 0 : _a.switchActiveMenuItem(value));
|
|
@@ -155,17 +164,21 @@ var SideMenuInner = forwardRef(function (_a, ref) {
|
|
|
155
164
|
}, transitionDuration + 200);
|
|
156
165
|
}
|
|
157
166
|
};
|
|
167
|
+
var shouldNotOpenOnHover = (isSeparatedMenu && isSeparatedMenuShown && isNarrowDesktop && manual) || isTouchScreen;
|
|
158
168
|
var handleMouseEnter = function () {
|
|
159
|
-
|
|
160
|
-
if ((isSeparatedMenu && isSeparatedMenuShown && isNarrowDesktop && manual) || isTouchScreen) {
|
|
169
|
+
if (shouldNotOpenOnHover) {
|
|
161
170
|
return;
|
|
162
171
|
}
|
|
172
|
+
setIsHovered(true);
|
|
163
173
|
if (isCollapsable && !isOpened && !isSeparatedMenuShown) {
|
|
164
174
|
isMouseOutside && showMinimizedRoot(false);
|
|
165
175
|
setIsMouseOutside(false);
|
|
166
176
|
}
|
|
167
177
|
};
|
|
168
178
|
var handleMouseLeave = function () {
|
|
179
|
+
if (shouldNotOpenOnHover) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
169
182
|
setIsHovered(false);
|
|
170
183
|
if (isCollapsable) {
|
|
171
184
|
handleIsOpened(false, !manual);
|
|
@@ -216,13 +229,11 @@ var SideMenuInner = forwardRef(function (_a, ref) {
|
|
|
216
229
|
return 'never';
|
|
217
230
|
};
|
|
218
231
|
var handleRightBorderClick = function () {
|
|
219
|
-
if (isCollapsable) {
|
|
220
|
-
setIsCollapsable(false);
|
|
221
|
-
}
|
|
222
|
-
else {
|
|
232
|
+
if (!isCollapsable) {
|
|
223
233
|
setIsOpened(false);
|
|
224
|
-
setIsCollapsable(true);
|
|
225
234
|
}
|
|
235
|
+
onPinnedValueChange === null || onPinnedValueChange === void 0 ? void 0 : onPinnedValueChange(!isCollapsable);
|
|
236
|
+
setIsCollapsable(!isCollapsable);
|
|
226
237
|
};
|
|
227
238
|
return (React.createElement(SideMenuContext.Provider, { value: {
|
|
228
239
|
isOpened: isOpened,
|
|
@@ -1,21 +1,24 @@
|
|
|
1
|
+
import { __assign } from "tslib";
|
|
1
2
|
import React, { forwardRef, useContext } from 'react';
|
|
2
3
|
import { SideMenuDataTids } from '../../SideMenuDataTids';
|
|
3
4
|
import { ArrowALeftIcon20Regular } from '@skbkontur/icons/icons/ArrowALeftIcon/ArrowALeftIcon20Regular';
|
|
4
5
|
import { SideMenuItem } from '../SideMenuItem/SideMenuItem';
|
|
5
6
|
import { SideMenuContext } from '../SideMenuContext';
|
|
7
|
+
import { navigationAttributeBackButton } from '../Navigation';
|
|
6
8
|
/**
|
|
7
9
|
* Кнопка возврата в меню первого уровня
|
|
8
10
|
*
|
|
9
11
|
* @visibleName BackButton
|
|
10
12
|
*/
|
|
11
13
|
var BackButton = forwardRef(function (_a, ref) {
|
|
14
|
+
var _b;
|
|
12
15
|
var caption = _a.caption, id = _a.id, href = _a.href;
|
|
13
16
|
var context = useContext(SideMenuContext);
|
|
14
17
|
var handleClick = function () {
|
|
15
18
|
var _a;
|
|
16
19
|
(_a = context.navigation) === null || _a === void 0 ? void 0 : _a.switchActiveMenuItem(id);
|
|
17
20
|
};
|
|
18
|
-
return (React.createElement(SideMenuItem, { "data-tid": SideMenuDataTids.backButton, icon: React.createElement(ArrowALeftIcon20Regular, null), caption: caption, _isSubMenu: true, onClick: handleClick, _isBackButton: true, ref: ref }));
|
|
21
|
+
return (React.createElement(SideMenuItem, __assign({ "data-tid": SideMenuDataTids.backButton, icon: React.createElement(ArrowALeftIcon20Regular, null), caption: caption, _isSubMenu: true, onClick: handleClick, _isBackButton: true, ref: ref }, (_b = {}, _b[navigationAttributeBackButton] = '', _b))));
|
|
19
22
|
});
|
|
20
23
|
BackButton.displayName = 'BackButton';
|
|
21
24
|
var BackButtonWithStaticFields = Object.assign(BackButton, { __KONTUR_REACT_UI__: 'BackButton' });
|