@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 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skbkontur/side-menu",
3
- "version": "2.0.2",
3
+ "version": "2.1.1",
4
4
  "publishConfig": {
5
5
  "access": "public",
6
6
  "registry": "https://registry.npmjs.org/"
@@ -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
- private readonly isCollapsable?;
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("[data-tid=" + SideMenuDataTids.clickableElement + "]")).filter(function (item) { return !item.querySelector("button[data-tid=" + SideMenuDataTids.backButton + "]"); });
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 = "[data-tid=" + SideMenuDataTids.clickableElement + "]";
120
- var separatedMenuSelector = "[data-tid=" + SideMenuDataTids.separatedSubMenu + "]";
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
  */
@@ -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, onValueChange = _a.onValueChange, activeItem = _a.activeItem, onActiveItemChange = _a.onActiveItemChange, _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, onOpen = _a.onOpen, onClose = _a.onClose, rest = __rest(_a, ["children", "value", "onValueChange", "activeItem", "onActiveItemChange", "size", "isSeparatedMenu", "className", "disableSwipe", "disableCollapsing", "desktopMediaQuery", "narrowDesktopMediaQuery", "tabletMediaQuery", "mobileMediaQuery", "hideScrollBar", "showScrollBar", "isOpen", "onOpen", "onClose"]);
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
- }, [isNarrowDesktop, isDesktopQuery, isTablet, isMobile]);
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
- setIsHovered(true);
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' });