@skbkontur/side-menu 1.12.7 → 1.12.9-any-level.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.
Files changed (49) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +0 -9
  3. package/SideMenuDataTids.d.ts +1 -0
  4. package/SideMenuDataTids.js +1 -0
  5. package/hooks/useAnimateOnMount.js +3 -2
  6. package/lib/theming/ThemeHelpers.js +14 -3
  7. package/lib/utils/scripts.d.ts +1 -10
  8. package/lib/utils/scripts.js +0 -75
  9. package/package.json +2 -2
  10. package/src/Navigation.d.ts +47 -0
  11. package/src/Navigation.js +146 -0
  12. package/src/SideMenu/SideMenu.js +44 -31
  13. package/src/SideMenu/SideMenu.styles.d.ts +1 -0
  14. package/src/SideMenu/SideMenu.styles.js +5 -2
  15. package/src/SideMenuBody/SideMenuBody.js +7 -9
  16. package/src/SideMenuContext.d.ts +2 -7
  17. package/src/SideMenuDropdown/SideMenuDropdown.d.ts +1 -3
  18. package/src/SideMenuDropdown/SideMenuDropdown.js +1 -1
  19. package/src/SideMenuFooter/SideMenuFooter.js +3 -11
  20. package/src/SideMenuHeader/SideMenuHeader.js +3 -2
  21. package/src/SideMenuSubItem/SideMenuSubItem.js +3 -16
  22. package/src/SideMenuSubLink/SideMenuSubLink.js +4 -17
  23. package/src/Tree.d.ts +17 -0
  24. package/src/Tree.js +133 -0
  25. package/src/internal/BackButton.d.ts +0 -1
  26. package/src/internal/BackButton.js +3 -15
  27. package/src/internal/ClickableElement.d.ts +1 -5
  28. package/src/internal/ClickableElement.js +45 -44
  29. package/src/internal/InnerSubMenu.d.ts +1 -1
  30. package/src/internal/InnerSubMenu.js +10 -19
  31. package/src/internal/ItemContent/Caption.d.ts +2 -1
  32. package/src/internal/ItemContent/Caption.js +6 -5
  33. package/src/internal/ItemContent/ItemContent.d.ts +3 -1
  34. package/src/internal/ItemContent/ItemContent.js +6 -4
  35. package/src/internal/NestedMenu.d.ts +2 -2
  36. package/src/internal/NestedMenu.js +6 -16
  37. package/src/internal/SeparatedSubMenu.d.ts +2 -3
  38. package/src/internal/SeparatedSubMenu.js +9 -37
  39. package/src/internal/SideMenuLogotype.js +3 -3
  40. package/src/internal/SubMenu.d.ts +1 -4
  41. package/src/internal/SubMenu.js +8 -10
  42. package/hooks/useActiveState.d.ts +0 -1
  43. package/hooks/useActiveState.js +0 -12
  44. package/hooks/useOpenedState.d.ts +0 -2
  45. package/hooks/useOpenedState.js +0 -14
  46. package/hooks/useOpenedSubElementState.d.ts +0 -1
  47. package/hooks/useOpenedSubElementState.js +0 -12
  48. package/src/internal/InnerBody.d.ts +0 -14
  49. package/src/internal/InnerBody.js +0 -108
@@ -1,17 +1,14 @@
1
1
  import { RefObject } from 'react';
2
- import { FlattedArrayElementType } from './internal/InnerBody';
3
2
  import { ScrollContainerScrollStateY } from '@skbkontur/react-ui';
4
3
  import { showScrollBarType } from './SideMenu/SideMenu';
4
+ import { MenuNavigation } from './Navigation';
5
5
  export interface SideMenuContextType {
6
6
  isBeingTransitioned?: boolean;
7
7
  isSeparatedMenu?: boolean;
8
8
  size?: 'small' | 'large';
9
- activeMenuItem?: string | null;
10
- switchActiveMenuItem?: (id: string) => void;
11
9
  clickedButton?: string | null;
12
10
  setClickedButton?: (id: string | null) => void;
13
11
  hasSubIcons?: boolean;
14
- openedParents?: string[];
15
12
  isDesktop?: boolean;
16
13
  isNarrowDesktop?: boolean;
17
14
  isTablet?: boolean;
@@ -21,9 +18,6 @@ export interface SideMenuContextType {
21
18
  isCollapsable?: boolean;
22
19
  toggleIsOpened?: () => void;
23
20
  setIsMinimized?: (isMinimized: boolean) => void;
24
- flattedArrayOfAllElements?: FlattedArrayElementType[];
25
- isSeparatedMenuShown?: boolean;
26
- setIsSeparatedMenuShown?: (separatedMenuIsShown: boolean) => void;
27
21
  setIsMouseOutside?: (v: boolean) => void;
28
22
  scrollState?: ScrollContainerScrollStateY;
29
23
  setScrollState?: (state: ScrollContainerScrollStateY) => void;
@@ -34,5 +28,6 @@ export interface SideMenuContextType {
34
28
  hideScrollBar?: boolean;
35
29
  showScrollBar?: showScrollBarType;
36
30
  sideMenuRef?: RefObject<HTMLDivElement>;
31
+ navigation?: MenuNavigation | null;
37
32
  }
38
33
  export declare const SideMenuContext: import("react").Context<SideMenuContextType>;
@@ -2,12 +2,10 @@ import React from 'react';
2
2
  import { DropdownMenuProps } from '@skbkontur/react-ui';
3
3
  import { CommonProps } from '@skbkontur/react-ui/internal/CommonWrapper';
4
4
  import { SideMenuItemProps } from '../SideMenuItem/SideMenuItem';
5
- export interface SideMenuDropdownProps extends CommonProps, Omit<DropdownMenuProps, 'caption' | 'disableAnimations'>, Pick<SideMenuItemProps, 'icon' | 'caption' | 'marker' | 'id' | '_generatedId' | 'subCaption' | '_isAvatar'> {
5
+ export interface SideMenuDropdownProps extends CommonProps, Omit<DropdownMenuProps, 'caption' | 'disableAnimations'>, Pick<SideMenuItemProps, 'icon' | 'caption' | 'marker' | 'id' | 'subCaption' | '_isAvatar'> {
6
6
  children?: React.ReactNode;
7
7
  disableAnimations?: boolean;
8
8
  id?: string;
9
- /** @ignore */
10
- _generatedId?: string;
11
9
  }
12
10
  /**
13
11
  * Элемент списка с выпадающим меню
@@ -8,7 +8,7 @@ import { SideMenuContext } from '../SideMenuContext';
8
8
  import { getSideMenuTheme } from '../../lib/theming/ThemeHelpers';
9
9
  var SideMenuDropdownInner = forwardRef(function (_a, ref) {
10
10
  var _b, _c;
11
- var icon = _a.icon, id = _a.id, _generatedId = _a._generatedId, children = _a.children, caption = _a.caption, marker = _a.marker, subCaption = _a.subCaption, className = _a.className, _d = _a.disableAnimations, disableAnimations = _d === void 0 ? false : _d, menuWidth = _a.menuWidth, _isAvatar = _a._isAvatar, rest = __rest(_a, ["icon", "id", "_generatedId", "children", "caption", "marker", "subCaption", "className", "disableAnimations", "menuWidth", "_isAvatar"]);
11
+ var icon = _a.icon, id = _a.id, children = _a.children, caption = _a.caption, marker = _a.marker, subCaption = _a.subCaption, className = _a.className, _d = _a.disableAnimations, disableAnimations = _d === void 0 ? false : _d, menuWidth = _a.menuWidth, _isAvatar = _a._isAvatar, rest = __rest(_a, ["icon", "id", "children", "caption", "marker", "subCaption", "className", "disableAnimations", "menuWidth", "_isAvatar"]);
12
12
  var context = useContext(SideMenuContext);
13
13
  var theme = getSideMenuTheme(useContext(ThemeContext));
14
14
  return (React.createElement("li", { className: cx((_b = {}, _b[jsStyles.wrapper()] = true, _b), className), ref: ref },
@@ -1,9 +1,8 @@
1
- import { __assign, __rest } from "tslib";
1
+ import { __assign, __read, __rest } from "tslib";
2
2
  import React, { forwardRef, useContext, useEffect, useState } from 'react';
3
3
  import { cx } from '@skbkontur/react-ui/lib/theming/Emotion';
4
4
  import { ThemeContext } from '@skbkontur/react-ui/lib/theming/ThemeContext';
5
5
  import { jsStyles } from './SideMenuFooter.styles';
6
- import { getItemId } from '../../lib/utils/scripts';
7
6
  import { SideMenuContext } from '../SideMenuContext';
8
7
  import { jsStylesForSideMenu } from '../SideMenu/SideMenu.styles';
9
8
  import { getSideMenuTheme } from '../../lib/theming/ThemeHelpers';
@@ -12,7 +11,7 @@ var SideMenuFooterInner = forwardRef(function (_a, ref) {
12
11
  var className = _a.className, children = _a.children, rest = __rest(_a, ["className", "children"]);
13
12
  var context = useContext(SideMenuContext);
14
13
  var theme = getSideMenuTheme(useContext(ThemeContext));
15
- var _c = useState(false), isFixed = _c[0], setIsFixed = _c[1];
14
+ var _c = __read(useState(false), 2), isFixed = _c[0], setIsFixed = _c[1];
16
15
  useEffect(function () {
17
16
  setIsFixed(!!context.hasScrollBar && !(context.scrollState === 'bottom'));
18
17
  }, [context.hasScrollBar, context.scrollState]);
@@ -22,14 +21,7 @@ var SideMenuFooterInner = forwardRef(function (_a, ref) {
22
21
  _b[jsStyles.rootFixed(theme)] = isFixed,
23
22
  _b[jsStyles.rootTransitionedForTabletsOrMobiles()] = context.isBeingTransitioned && (context.isMobile || context.isTablet),
24
23
  _b), className), ref: ref }, rest),
25
- React.createElement("ul", { className: jsStylesForSideMenu.list() }, React.Children.map(children, function (child, index) {
26
- if (React.isValidElement(child)) {
27
- return React.cloneElement(child, {
28
- _generatedId: getItemId('footer', index++),
29
- });
30
- }
31
- return child;
32
- }))));
24
+ React.createElement("ul", { className: jsStylesForSideMenu.list() }, children)));
33
25
  }
34
26
  return null;
35
27
  });
@@ -10,7 +10,8 @@ import { getSideMenuTheme } from '../../lib/theming/ThemeHelpers';
10
10
  import { getDOMRect } from '@skbkontur/react-ui/lib/dom/getDOMRect';
11
11
  var SideMenuHeaderInner = forwardRef(function (_a, ref) {
12
12
  var _b;
13
- var className = _a.className, productLogo = _a.productLogo, konturLogo = _a.konturLogo, iconUrl = _a.iconUrl, style = _a.style, _c = _a.withWidget, withWidget = _c === void 0 ? true : _c, dataTid = _a["data-tid"], rest = __rest(_a, ["className", "productLogo", "konturLogo", "iconUrl", "style", "withWidget", 'data-tid']);
13
+ var _c;
14
+ var className = _a.className, productLogo = _a.productLogo, konturLogo = _a.konturLogo, iconUrl = _a.iconUrl, style = _a.style, _d = _a.withWidget, withWidget = _d === void 0 ? true : _d, dataTid = _a["data-tid"], rest = __rest(_a, ["className", "productLogo", "konturLogo", "iconUrl", "style", "withWidget", 'data-tid']);
14
15
  var context = useContext(SideMenuContext);
15
16
  var theme = getSideMenuTheme(useContext(ThemeContext));
16
17
  var headerWrapperRef = useRef(null);
@@ -25,7 +26,7 @@ var SideMenuHeaderInner = forwardRef(function (_a, ref) {
25
26
  _b[jsStyles.rootForTabletsOrMobiles(theme)] = context.isMobile || context.isTablet,
26
27
  _b[jsStyles.fixedRoot(theme)] = context.isOpened && !!context.hasScrollBar && !(context.scrollState === 'top'),
27
28
  _b[jsStyles.collapsedRootForTabletsOrMobiles()] = !context.isOpened && (context.isMobile || context.isTablet),
28
- _b[jsStyles.rootWithSeparatedMenuShown(theme)] = context.isOpened && context.isMobile && context.isSeparatedMenuShown,
29
+ _b[jsStyles.rootWithSeparatedMenuShown(theme)] = context.isOpened && context.isMobile && ((_c = context.navigation) === null || _c === void 0 ? void 0 : _c.isSeparatedMenuShown),
29
30
  _b), className), ref: mergeRefs([headerWrapperRef, ref]), style: style, "data-tid": dataTid },
30
31
  React.createElement(SideMenuLogotype, __assign({ productLogo: productLogo, konturLogo: konturLogo, iconUrl: iconUrl, withWidget: withWidget }, rest))));
31
32
  });
@@ -1,23 +1,10 @@
1
1
  import { __assign, __rest } from "tslib";
2
- import React, { forwardRef, useContext } from 'react';
2
+ import React, { forwardRef } from 'react';
3
3
  import { SideMenuItem } from '../SideMenuItem/SideMenuItem';
4
- import { SideMenuContext } from '../SideMenuContext';
5
- import { NestedMenu } from '../internal/NestedMenu';
6
- import { useOpenedSubElementState } from '../../hooks/useOpenedSubElementState';
7
- import { useMemoIcon } from '../../hooks/useMemoIcon';
8
4
  var SideMenuSubItemInner = forwardRef(function (_a, ref) {
9
- var children = _a.children, _generatedId = _a._generatedId, id = _a.id, rest = __rest(_a, ["children", "_generatedId", "id"]);
10
- var context = useContext(SideMenuContext);
11
- var isOpened = useOpenedSubElementState(id, _generatedId, context.openedParents, context.activeMenuItem);
12
- var isOpenedButton = useOpenedSubElementState(id, _generatedId, context.openedParents, context.clickedButton);
13
- var icon = useMemoIcon(children, isOpened || isOpenedButton);
5
+ var props = __rest(_a, []);
14
6
  return (React.createElement("li", { ref: ref },
15
- React.createElement(SideMenuItem
16
- /*@ts-expect-error: SideMenuItem should have icon */
17
- , __assign({
18
- /*@ts-expect-error: SideMenuItem should have icon */
19
- icon: icon, _isSubMenu: true, id: id, _generatedId: _generatedId, "aria-expanded": children ? isOpened || isOpenedButton : undefined, "aria-controls": children ? "" + (id || _generatedId) : undefined }, rest)),
20
- children && (isOpened || isOpenedButton) && (React.createElement(NestedMenu, { _generatedId: _generatedId, htmlId: "" + (id || _generatedId) }, children))));
7
+ React.createElement(SideMenuItem, __assign({ _isSubMenu: true }, props))));
21
8
  });
22
9
  SideMenuSubItemInner.displayName = 'SideMenuSubItem';
23
10
  /**
@@ -1,22 +1,9 @@
1
- import { __assign, __rest } from "tslib";
2
- import React, { forwardRef, useContext } from 'react';
3
- import { SideMenuContext } from '../SideMenuContext';
1
+ import { __assign } from "tslib";
2
+ import React, { forwardRef } from 'react';
4
3
  import { SideMenuLink } from '../SideMenuLink/SideMenuLink';
5
- import { NestedMenu } from '../internal/NestedMenu';
6
- import { useOpenedSubElementState } from '../../hooks/useOpenedSubElementState';
7
- import { useMemoIcon } from '../../hooks/useMemoIcon';
8
- var SideMenuSubLinkInner = forwardRef(function (_a, ref) {
9
- var id = _a.id, _generatedId = _a._generatedId, _isSubMenu = _a._isSubMenu, _isNestedSubMenu = _a._isNestedSubMenu, children = _a.children, rest = __rest(_a, ["id", "_generatedId", "_isSubMenu", "_isNestedSubMenu", "children"]);
10
- var context = useContext(SideMenuContext);
11
- var isOpened = useOpenedSubElementState(id, _generatedId, context.openedParents, context.activeMenuItem);
12
- var icon = useMemoIcon(children, isOpened);
4
+ var SideMenuSubLinkInner = forwardRef(function (props, ref) {
13
5
  return (React.createElement("li", { ref: ref },
14
- React.createElement(SideMenuLink
15
- /*@ts-expect-error: SideMenuItem should have icon */
16
- , __assign({
17
- /*@ts-expect-error: SideMenuItem should have icon */
18
- icon: icon, _isSubMenu: true, _isNestedSubMenu: _isNestedSubMenu, id: id, _generatedId: _generatedId, "aria-expanded": children ? isOpened : undefined, "aria-controls": children ? "" + (id || _generatedId) : undefined }, rest)),
19
- children && isOpened && (React.createElement(NestedMenu, { _generatedId: _generatedId, htmlId: "" + (id || _generatedId) }, children))));
6
+ React.createElement(SideMenuLink, __assign({ _isSubMenu: true }, props))));
20
7
  });
21
8
  SideMenuSubLinkInner.displayName = 'SideMenuSubLink';
22
9
  /**
package/src/Tree.d.ts ADDED
@@ -0,0 +1,17 @@
1
+ import { NavigableElement } from './Navigation';
2
+ export declare class TreeNode {
3
+ id: string;
4
+ value: NavigableElement | null;
5
+ parent: TreeNode | null;
6
+ children: TreeNode[];
7
+ constructor(id: string, value?: NavigableElement | null, parent?: TreeNode | null);
8
+ get hasChildren(): boolean;
9
+ }
10
+ export declare class Tree {
11
+ private root;
12
+ constructor(id: string, value?: NavigableElement | null);
13
+ preOrderTraversal(node?: TreeNode): Generator<TreeNode, void, undefined>;
14
+ insert(parentId: string, id: string | undefined | null, value?: NavigableElement | null): boolean;
15
+ remove(id: string): boolean;
16
+ find(id?: string | null): TreeNode | undefined;
17
+ }
package/src/Tree.js ADDED
@@ -0,0 +1,133 @@
1
+ import { __generator, __values } from "tslib";
2
+ var TreeNode = /** @class */ (function () {
3
+ function TreeNode(id, value, parent) {
4
+ if (value === void 0) { value = null; }
5
+ if (parent === void 0) { parent = null; }
6
+ this.id = id;
7
+ this.value = value;
8
+ this.parent = parent;
9
+ this.children = [];
10
+ }
11
+ Object.defineProperty(TreeNode.prototype, "hasChildren", {
12
+ get: function () {
13
+ return this.children.length !== 0;
14
+ },
15
+ enumerable: false,
16
+ configurable: true
17
+ });
18
+ return TreeNode;
19
+ }());
20
+ export { TreeNode };
21
+ var Tree = /** @class */ (function () {
22
+ function Tree(id, value) {
23
+ if (value === void 0) { value = null; }
24
+ this.root = new TreeNode(id, value);
25
+ }
26
+ Tree.prototype.preOrderTraversal = function (node) {
27
+ var _a, _b, child, e_1_1;
28
+ var e_1, _c;
29
+ if (node === void 0) { node = this.root; }
30
+ return __generator(this, function (_d) {
31
+ switch (_d.label) {
32
+ case 0: return [4 /*yield*/, node];
33
+ case 1:
34
+ _d.sent();
35
+ if (!node.children.length) return [3 /*break*/, 9];
36
+ _d.label = 2;
37
+ case 2:
38
+ _d.trys.push([2, 7, 8, 9]);
39
+ _a = __values(node.children), _b = _a.next();
40
+ _d.label = 3;
41
+ case 3:
42
+ if (!!_b.done) return [3 /*break*/, 6];
43
+ child = _b.value;
44
+ return [5 /*yield**/, __values(this.preOrderTraversal(child))];
45
+ case 4:
46
+ _d.sent();
47
+ _d.label = 5;
48
+ case 5:
49
+ _b = _a.next();
50
+ return [3 /*break*/, 3];
51
+ case 6: return [3 /*break*/, 9];
52
+ case 7:
53
+ e_1_1 = _d.sent();
54
+ e_1 = { error: e_1_1 };
55
+ return [3 /*break*/, 9];
56
+ case 8:
57
+ try {
58
+ if (_b && !_b.done && (_c = _a.return)) _c.call(_a);
59
+ }
60
+ finally { if (e_1) throw e_1.error; }
61
+ return [7 /*endfinally*/];
62
+ case 9: return [2 /*return*/];
63
+ }
64
+ });
65
+ };
66
+ Tree.prototype.insert = function (parentId, id, value) {
67
+ var e_2, _a;
68
+ if (value === void 0) { value = null; }
69
+ if (!id)
70
+ return false;
71
+ try {
72
+ for (var _b = __values(this.preOrderTraversal()), _c = _b.next(); !_c.done; _c = _b.next()) {
73
+ var node = _c.value;
74
+ if (node.id === parentId && node.children.every(function (node) { return node.id !== id; })) {
75
+ node.children.push(new TreeNode(id, value, node));
76
+ return true;
77
+ }
78
+ }
79
+ }
80
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
81
+ finally {
82
+ try {
83
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
84
+ }
85
+ finally { if (e_2) throw e_2.error; }
86
+ }
87
+ return false;
88
+ };
89
+ Tree.prototype.remove = function (id) {
90
+ var e_3, _a;
91
+ try {
92
+ for (var _b = __values(this.preOrderTraversal()), _c = _b.next(); !_c.done; _c = _b.next()) {
93
+ var node = _c.value;
94
+ var filtered = node.children.filter(function (c) { return c.id !== id; });
95
+ if (filtered.length !== node.children.length) {
96
+ node.children = filtered;
97
+ return true;
98
+ }
99
+ }
100
+ }
101
+ catch (e_3_1) { e_3 = { error: e_3_1 }; }
102
+ finally {
103
+ try {
104
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
105
+ }
106
+ finally { if (e_3) throw e_3.error; }
107
+ }
108
+ return false;
109
+ };
110
+ Tree.prototype.find = function (id) {
111
+ var e_4, _a;
112
+ if (!id) {
113
+ return undefined;
114
+ }
115
+ try {
116
+ for (var _b = __values(this.preOrderTraversal()), _c = _b.next(); !_c.done; _c = _b.next()) {
117
+ var node = _c.value;
118
+ if (node.id === id)
119
+ return node;
120
+ }
121
+ }
122
+ catch (e_4_1) { e_4 = { error: e_4_1 }; }
123
+ finally {
124
+ try {
125
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
126
+ }
127
+ finally { if (e_4) throw e_4.error; }
128
+ }
129
+ return undefined;
130
+ };
131
+ return Tree;
132
+ }());
133
+ export { Tree };
@@ -2,7 +2,6 @@ import React from 'react';
2
2
  import { CommonClickableElementProps } from './ClickableElement';
3
3
  export interface BackButtonProps extends Pick<CommonClickableElementProps, 'caption' | 'id'> {
4
4
  href?: string;
5
- generatedId?: string;
6
5
  }
7
6
  declare const BackButtonWithStaticFields: React.ForwardRefExoticComponent<BackButtonProps & React.RefAttributes<HTMLButtonElement>> & {
8
7
  __KONTUR_REACT_UI__: string;
@@ -9,23 +9,11 @@ import { SideMenuContext } from '../SideMenuContext';
9
9
  * @visibleName BackButton
10
10
  */
11
11
  var BackButton = forwardRef(function (_a, ref) {
12
- var caption = _a.caption, id = _a.id, href = _a.href, generatedId = _a.generatedId;
12
+ var caption = _a.caption, id = _a.id, href = _a.href;
13
13
  var context = useContext(SideMenuContext);
14
14
  var handleClick = function () {
15
- var _a, _b, _c, _d;
16
- var currentId = id || href || generatedId;
17
- if (context.activeMenuItem === currentId) {
18
- (_a = context.setIsSeparatedMenuShown) === null || _a === void 0 ? void 0 : _a.call(context, false);
19
- }
20
- if (id) {
21
- return (_b = context.switchActiveMenuItem) === null || _b === void 0 ? void 0 : _b.call(context, id);
22
- }
23
- if (href) {
24
- return (_c = context.switchActiveMenuItem) === null || _c === void 0 ? void 0 : _c.call(context, href);
25
- }
26
- if (generatedId) {
27
- return (_d = context.switchActiveMenuItem) === null || _d === void 0 ? void 0 : _d.call(context, generatedId);
28
- }
15
+ var _a;
16
+ (_a = context.navigation) === null || _a === void 0 ? void 0 : _a.switchActiveMenuItem(id);
29
17
  };
30
18
  return (React.createElement(SideMenuItem, { "data-tid": SideMenuDataTids.backButton, icon: React.createElement(ArrowALeftIcon20Regular, null), caption: caption, _isSubMenu: true, onClick: handleClick, _isBackButton: true, ref: ref }));
31
19
  });
@@ -10,12 +10,8 @@ export interface CommonClickableElementProps extends CommonProps {
10
10
  isButton?: boolean;
11
11
  disabled?: boolean;
12
12
  /** @ignore */
13
- _generatedId?: string;
14
- /** @ignore */
15
13
  _isSubMenu?: boolean;
16
14
  /** @ignore */
17
- _isNestedSubMenu?: boolean;
18
- /** @ignore */
19
15
  _isDropdown?: boolean;
20
16
  /** @ignore */
21
17
  _isAvatar?: boolean;
@@ -30,7 +26,7 @@ export interface ClickableElementProps extends CommonClickableElementProps {
30
26
  onFocus?: React.EventHandler<React.FocusEvent>;
31
27
  onBlur?: React.EventHandler<React.FocusEvent>;
32
28
  }
33
- declare const ClickableElementWithStaticFields: React.ForwardRefExoticComponent<ClickableElementProps & React.RefAttributes<HTMLButtonElement | HTMLAnchorElement>> & {
29
+ declare const ClickableElementWithStaticFields: React.ForwardRefExoticComponent<ClickableElementProps & React.RefAttributes<HTMLAnchorElement | HTMLButtonElement>> & {
34
30
  __KONTUR_REACT_UI__: string;
35
31
  };
36
32
  export { ClickableElementWithStaticFields as ClickableElement };
@@ -1,15 +1,15 @@
1
- import { __assign, __rest } from "tslib";
2
- import React, { forwardRef, useContext, useState } from 'react';
1
+ import { __assign, __read, __rest } from "tslib";
2
+ import React, { forwardRef, useContext, useEffect, useState } from 'react';
3
3
  import { keyListener } from '@skbkontur/react-ui/lib/events/keyListener';
4
4
  import { SideMenuContext } from '../SideMenuContext';
5
5
  import { ItemContent } from './ItemContent/ItemContent';
6
6
  import { SubMenu } from './SubMenu';
7
- import { useOpenedState } from '../../hooks/useOpenedState';
8
- import { useActiveState } from '../../hooks/useActiveState';
9
7
  import { jsStyles } from './ClickableElement.styles';
10
8
  import { cx } from '@skbkontur/react-ui/lib/theming/Emotion';
11
9
  import { getSideMenuTheme } from '../../lib/theming/ThemeHelpers';
12
10
  import { ThemeContext } from '@skbkontur/react-ui';
11
+ import { useMemoIcon } from '../../hooks/useMemoIcon';
12
+ import { SideMenuDataTids } from '../../SideMenuDataTids';
13
13
  /**
14
14
  * Элемент списка (пункт меню либо ссылка)
15
15
  *
@@ -17,31 +17,35 @@ import { ThemeContext } from '@skbkontur/react-ui';
17
17
  */
18
18
  var ClickableElement = forwardRef(function (_a, ref) {
19
19
  var _b;
20
- var onClick = _a.onClick, icon = _a.icon, marker = _a.marker, caption = _a.caption, subCaption = _a.subCaption, id = _a.id, _isSubMenu = _a._isSubMenu, children = _a.children, _isNestedSubMenu = _a._isNestedSubMenu, _generatedId = _a._generatedId, Tag = _a.element, onKeyDown = _a.onKeyDown, onFocus = _a.onFocus, onBlur = _a.onBlur, className = _a.className, _isDropdown = _a._isDropdown, _isBackButton = _a._isBackButton, _isAvatar = _a._isAvatar, isButton = _a.isButton, href = _a.href, disabled = _a.disabled, rest = __rest(_a, ["onClick", "icon", "marker", "caption", "subCaption", "id", "_isSubMenu", "children", "_isNestedSubMenu", "_generatedId", "element", "onKeyDown", "onFocus", "onBlur", "className", "_isDropdown", "_isBackButton", "_isAvatar", "isButton", "href", "disabled"]);
20
+ var onClick = _a.onClick, icon = _a.icon, marker = _a.marker, caption = _a.caption, subCaption = _a.subCaption, id = _a.id, _isSubMenu = _a._isSubMenu, children = _a.children, Tag = _a.element, onKeyDown = _a.onKeyDown, onFocus = _a.onFocus, onBlur = _a.onBlur, className = _a.className, _isDropdown = _a._isDropdown, _isBackButton = _a._isBackButton, _isAvatar = _a._isAvatar, isButton = _a.isButton, href = _a.href, disabled = _a.disabled, rest = __rest(_a, ["onClick", "icon", "marker", "caption", "subCaption", "id", "_isSubMenu", "children", "element", "onKeyDown", "onFocus", "onBlur", "className", "_isDropdown", "_isBackButton", "_isAvatar", "isButton", "href", "disabled"]);
21
21
  var context = useContext(SideMenuContext);
22
22
  var theme = getSideMenuTheme(useContext(ThemeContext));
23
- var isActive = !isButton && useActiveState(id, href, _generatedId, context.activeMenuItem);
24
- var isClickedButton = isButton && useActiveState(id, href, _generatedId, context.clickedButton);
25
- var _c = useState(false), isFocusedByTab = _c[0], setIsFocusedByTab = _c[1];
26
- var isOpened = useOpenedState(id || href, _generatedId, context.openedParents, isActive || isClickedButton, children, context.isSeparatedMenuShown, context.isMobile && context.isSeparatedMenu);
27
- var hasChildren = function (id, generatedId) {
28
- var _a, _b;
29
- var parentId = id ? 'parentId' : 'generatedParentId';
30
- var childId = id !== null && id !== void 0 ? id : generatedId;
31
- return (_b = (_a = context.flattedArrayOfAllElements) === null || _a === void 0 ? void 0 : _a.filter(function (el) { return el[parentId] === childId; })) === null || _b === void 0 ? void 0 : _b.length;
32
- };
33
- var switchItem = function (context, isButton, id, href, _generatedId) {
34
- var _a, _b;
35
- var itemId = id || href || _generatedId;
36
- if (!itemId)
37
- return;
38
- if (!isButton) {
39
- (_a = context.switchActiveMenuItem) === null || _a === void 0 ? void 0 : _a.call(context, itemId);
40
- }
41
- else {
42
- (_b = context.setClickedButton) === null || _b === void 0 ? void 0 : _b.call(context, itemId);
23
+ var _c = __read(useState(false), 2), isActive = _c[0], setIsActive = _c[1];
24
+ var _d = __read(useState(false), 2), isFirstLevelParentOfActiveMenuItem = _d[0], setIsFirstLevelParentOfActiveMenuItem = _d[1];
25
+ var _e = __read(useState(false), 2), isOpened = _e[0], setIsOpened = _e[1];
26
+ var _f = __read(useState(false), 2), isNestedSubMenu = _f[0], setIsNestedSubMenu = _f[1];
27
+ var _g = __read(useState(false), 2), hasSubIcons = _g[0], setHasSubIcons = _g[1];
28
+ var _h = __read(useState(false), 2), isFocusedByTab = _h[0], setIsFocusedByTab = _h[1];
29
+ var _j = __read(useState(id || href || ''), 2), currentId = _j[0], setCurrentId = _j[1];
30
+ useEffect(function () {
31
+ var _a;
32
+ if (!currentId) {
33
+ var generatedId = Date.now().toString(36) + Math.random().toString(36).substr(2);
34
+ setCurrentId(generatedId);
43
35
  }
44
- };
36
+ (_a = context.navigation) === null || _a === void 0 ? void 0 : _a.addValue(currentId, {
37
+ setIsActive: setIsActive,
38
+ setIsOpened: setIsOpened,
39
+ isSubMenu: _isSubMenu,
40
+ setIsNestedSubMenu: setIsNestedSubMenu,
41
+ setHasSubIcons: setHasSubIcons,
42
+ setIsFirstLevelParentOfActiveMenuItem: setIsFirstLevelParentOfActiveMenuItem,
43
+ });
44
+ return function () {
45
+ var _a;
46
+ (_a = context.navigation) === null || _a === void 0 ? void 0 : _a.updateNavigationTree();
47
+ };
48
+ });
45
49
  var toggleIsShown = function (lastElementInTheHierarchy) {
46
50
  var _a;
47
51
  if ((context.isMobile || context.isTablet) && lastElementInTheHierarchy) {
@@ -67,21 +71,16 @@ var ClickableElement = forwardRef(function (_a, ref) {
67
71
  }
68
72
  };
69
73
  var handleClick = function (e) {
70
- var _a;
74
+ var _a, _b, _c;
71
75
  if (disabled) {
72
76
  return;
73
77
  }
74
78
  onClick === null || onClick === void 0 ? void 0 : onClick(e);
75
- if (_isBackButton) {
79
+ if (_isBackButton || _isDropdown) {
76
80
  return;
77
81
  }
78
- var currentId = id || href || _generatedId;
79
- var isMobileWithClosedSeparatedMenu = context.isMobile && context.isSeparatedMenu && !context.isSeparatedMenuShown;
80
- if (isMobileWithClosedSeparatedMenu && context.activeMenuItem === currentId) {
81
- (_a = context.setIsSeparatedMenuShown) === null || _a === void 0 ? void 0 : _a.call(context, true);
82
- }
83
- var lastElementInTheHierarchy = !hasChildren(id || href, _generatedId) && !_isDropdown && !_isBackButton;
84
- switchItem(context, isButton, id, href, _generatedId);
82
+ (_a = context.navigation) === null || _a === void 0 ? void 0 : _a.switchActiveMenuItem(currentId, isButton);
83
+ var lastElementInTheHierarchy = !_isDropdown && !_isBackButton && !((_c = (_b = context.navigation) === null || _b === void 0 ? void 0 : _b.activeMenuItemTreeNode) === null || _c === void 0 ? void 0 : _c.hasChildren);
85
84
  toggleIsShown(lastElementInTheHierarchy);
86
85
  setIsMinimized(lastElementInTheHierarchy);
87
86
  setMouseIsOutside(lastElementInTheHierarchy);
@@ -98,24 +97,26 @@ var ClickableElement = forwardRef(function (_a, ref) {
98
97
  onBlur === null || onBlur === void 0 ? void 0 : onBlur(e);
99
98
  setIsFocusedByTab(false);
100
99
  };
101
- var shouldHighlightTopLevelItemWhenSubItemSelectedInSeparatedMenu = isOpened && !_isSubMenu && context.isSeparatedMenu;
102
- var shouldHighlightTopLevelItemWhenMenuIsMinimized = isOpened && !_isSubMenu && context.isCollapsable && !context.isOpened;
103
100
  var Component = _isSubMenu || _isDropdown ? 'div' : 'li';
101
+ var isHighlighted = isActive ||
102
+ (isFirstLevelParentOfActiveMenuItem && !context.isOpened && context.isCollapsable) ||
103
+ (isFirstLevelParentOfActiveMenuItem && context.isSeparatedMenu);
104
104
  var newProps = __assign({ className: cx((_b = {},
105
105
  _b[jsStyles.root(theme)] = true,
106
106
  _b[jsStyles.rootButton(theme)] = isButton,
107
107
  _b[jsStyles.rootSubItemInSeparatedSubMenu(theme)] = context.isSeparatedMenu && _isSubMenu,
108
108
  _b[jsStyles.focusedRoot(theme)] = isFocusedByTab,
109
109
  _b[jsStyles.disabledRoot(theme)] = disabled,
110
- _b[jsStyles.activeRoot(theme)] = isActive ||
111
- shouldHighlightTopLevelItemWhenSubItemSelectedInSeparatedMenu ||
112
- shouldHighlightTopLevelItemWhenMenuIsMinimized,
110
+ _b[jsStyles.activeRoot(theme)] = isHighlighted,
113
111
  _b[jsStyles.activeRootSubItemInSeparatedSubMenu(theme)] = isActive && context.isSeparatedMenu && _isSubMenu,
114
- _b), className), onClick: handleClick, onFocus: handleFocus, onBlur: handleBlur, children: (React.createElement(ItemContent, { _isSubMenu: _isSubMenu, icon: icon, _isNestedSubMenu: _isNestedSubMenu, caption: caption, subCaption: subCaption, marker: marker, _isBackButton: _isBackButton, _isDropdown: _isDropdown, _isAvatar: _isAvatar, disabled: disabled })), ref: ref, href: href }, rest);
115
- return (React.createElement(Component, null,
112
+ _b), className), onClick: handleClick, onFocus: handleFocus, onBlur: handleBlur, children: (React.createElement(ItemContent, { _isSubMenu: _isSubMenu,
113
+ // @ts-expect-error: SideMenuItem should have icon
114
+ icon: _isSubMenu && !_isBackButton ? useMemoIcon(children, isOpened) : icon, isNestedSubMenu: isNestedSubMenu, caption: caption, subCaption: subCaption, marker: marker, _isBackButton: _isBackButton, _isDropdown: _isDropdown, _isAvatar: _isAvatar, disabled: disabled })), ref: ref, href: href }, rest);
115
+ return (React.createElement(Component, { "data-tid": SideMenuDataTids.clickableElement, "data-navigation-id": currentId },
116
116
  React.cloneElement(React.createElement(Tag, { state: isActive ? 'active' : undefined }), children
117
- ? __assign(__assign({}, newProps), { 'aria-expanded': isOpened, 'aria-controls': "" + (id || _generatedId) }) : __assign({}, newProps)),
118
- React.createElement(SubMenu, { generatedId: _generatedId, id: id, href: href, caption: caption, isSubMenu: _isSubMenu, isSeparatedMenu: context.isSeparatedMenu, isOpened: isOpened, isMinimized: !context.isOpened && !(context.isMobile || context.isTablet), htmlId: "" + (id || _generatedId) }, children)));
117
+ ? __assign(__assign({}, newProps), { 'aria-expanded': children ? isOpened : undefined, 'aria-controls': children ? currentId : undefined }) : __assign({}, newProps)),
118
+ React.createElement(SubMenu, { caption: caption, isSubMenu: _isSubMenu, isSeparatedMenu: context.isSeparatedMenu, htmlId: currentId, isOpened: isOpened },
119
+ React.createElement(SideMenuContext.Provider, { value: __assign({ hasSubIcons: hasSubIcons }, context) }, children))));
119
120
  });
120
121
  ClickableElement.displayName = 'ClickableElement';
121
122
  var ClickableElementWithStaticFields = Object.assign(ClickableElement, {
@@ -1,8 +1,8 @@
1
1
  import React from 'react';
2
2
  interface InnerSubMenuProps {
3
3
  children?: React.ReactNode;
4
- generatedId?: string;
5
4
  htmlId: string;
5
+ isOpened?: boolean;
6
6
  }
7
7
  declare const InnerSubMenuWithStaticFields: React.ForwardRefExoticComponent<InnerSubMenuProps & React.RefAttributes<HTMLUListElement>> & {
8
8
  __KONTUR_REACT_UI__: string;
@@ -1,29 +1,20 @@
1
- import React, { forwardRef } from 'react';
2
- import { isClickableSubElement } from '../../lib/utils/scripts';
1
+ import React, { forwardRef, useContext } from 'react';
3
2
  import { jsStylesForSideMenu } from '../SideMenu/SideMenu.styles';
3
+ import { cx } from '@skbkontur/react-ui/lib/theming/Emotion';
4
+ import { SideMenuContext } from '../SideMenuContext';
4
5
  /**
5
6
  * Подменю, раскрывающееся внутри основного меню
6
7
  *
7
8
  * @visibleName InnerSubMenu
8
9
  */
9
10
  var InnerSubMenu = forwardRef(function (_a, ref) {
10
- var children = _a.children, generatedId = _a.generatedId, htmlId = _a.htmlId;
11
- var levelIndex = 0;
12
- return (React.createElement("ul", { ref: ref, id: htmlId, className: jsStylesForSideMenu.list() }, React.Children.map(children, function (child) {
13
- if (React.isValidElement(child)) {
14
- if (
15
- // @ts-expect-error: accessing private property
16
- isClickableSubElement(child.type.__KONTUR_REACT_UI__)) {
17
- var oldIndex = levelIndex;
18
- levelIndex++;
19
- return React.cloneElement(child, {
20
- _generatedId: generatedId + "-" + oldIndex,
21
- });
22
- }
23
- return React.cloneElement(child);
24
- }
25
- return child;
26
- })));
11
+ var _b;
12
+ var children = _a.children, htmlId = _a.htmlId, isOpened = _a.isOpened;
13
+ var context = useContext(SideMenuContext);
14
+ return (React.createElement("ul", { ref: ref, id: htmlId, className: cx((_b = {},
15
+ _b[jsStylesForSideMenu.list()] = true,
16
+ _b[jsStylesForSideMenu.hidden()] = !isOpened || !context.isOpened,
17
+ _b)) }, children));
27
18
  });
28
19
  InnerSubMenu.displayName = 'InnerSubMenu';
29
20
  var InnerSubMenuWithStaticFields = Object.assign(InnerSubMenu, { __KONTUR_REACT_UI__: 'InnerSubMenu' });
@@ -1,8 +1,9 @@
1
1
  import React from 'react';
2
2
  import { SideMenuItemProps } from '../../SideMenuItem/SideMenuItem';
3
- interface CaptionProps extends Pick<SideMenuItemProps, '_isSubMenu' | '_isNestedSubMenu' | 'caption' | '_isBackButton' | '_isDropdown' | '_isAvatar' | 'subCaption'> {
3
+ interface CaptionProps extends Pick<SideMenuItemProps, '_isSubMenu' | 'caption' | '_isBackButton' | '_isDropdown' | '_isAvatar' | 'subCaption'> {
4
4
  hasIcon: boolean;
5
5
  isMultiline: boolean;
6
+ isNestedSubMenu?: boolean;
6
7
  }
7
8
  export declare const Caption: React.ForwardRefExoticComponent<CaptionProps & React.RefAttributes<HTMLParagraphElement>>;
8
9
  export {};
@@ -1,3 +1,4 @@
1
+ import { __read } from "tslib";
1
2
  import { cx } from '@skbkontur/react-ui/lib/theming/Emotion';
2
3
  import { ThemeContext } from '@skbkontur/react-ui/lib/theming/ThemeContext';
3
4
  import { jsStyles } from './Caption.styles';
@@ -5,7 +6,7 @@ import React, { forwardRef, useContext, useEffect, useRef, useState } from 'reac
5
6
  import { SideMenuContext } from '../../SideMenuContext';
6
7
  import { getSideMenuTheme } from '../../../lib/theming/ThemeHelpers';
7
8
  var getTruncatedUserName = function (caption, visibleWidth, fullWidth) {
8
- var _a = caption.split(' '), firstName = _a[0], lastName = _a[1];
9
+ var _a = __read(caption.split(' '), 2), firstName = _a[0], lastName = _a[1];
9
10
  if (visibleWidth < fullWidth && lastName) {
10
11
  return firstName + " " + lastName[0] + ".";
11
12
  }
@@ -22,11 +23,11 @@ var getCaptionTail = function (caption, visibleWidth, fullWidth) {
22
23
  };
23
24
  export var Caption = forwardRef(function (_a, ref) {
24
25
  var _b, _c;
25
- var _isSubMenu = _a._isSubMenu, _isNestedSubMenu = _a._isNestedSubMenu, hasIcon = _a.hasIcon, caption = _a.caption, subCaption = _a.subCaption, isMultiline = _a.isMultiline, _isBackButton = _a._isBackButton, _isDropdown = _a._isDropdown, _isAvatar = _a._isAvatar;
26
+ var _isSubMenu = _a._isSubMenu, isNestedSubMenu = _a.isNestedSubMenu, hasIcon = _a.hasIcon, caption = _a.caption, subCaption = _a.subCaption, isMultiline = _a.isMultiline, _isBackButton = _a._isBackButton, _isDropdown = _a._isDropdown, _isAvatar = _a._isAvatar;
26
27
  var theme = getSideMenuTheme(useContext(ThemeContext));
27
28
  var _d = useContext(SideMenuContext), isBeingTransitioned = _d.isBeingTransitioned, isSeparatedMenu = _d.isSeparatedMenu, size = _d.size, isTouchScreen = _d.isTouchScreen, hasSubIcons = _d.hasSubIcons;
28
29
  var captionRef = useRef(null);
29
- var _e = useState(''), tail = _e[0], setTail = _e[1];
30
+ var _e = __read(useState(''), 2), tail = _e[0], setTail = _e[1];
30
31
  var isCaptionPlainText = typeof caption === 'string';
31
32
  useEffect(function () {
32
33
  if (!_isDropdown || !captionRef.current || !caption || !isCaptionPlainText) {
@@ -58,8 +59,8 @@ export var Caption = forwardRef(function (_a, ref) {
58
59
  _isDropdown &&
59
60
  (!_isAvatar || isAvatarCaptionSingleWord(caption, _isAvatar)),
60
61
  _c[jsStyles.captionSubItem(theme)] = _isSubMenu,
61
- _c[jsStyles.captionSubItemSeparatedMenuTopLevel()] = isSeparatedMenu && !_isNestedSubMenu && _isSubMenu && !hasIcon,
62
- _c[jsStyles.captionNestedItemSeparatedMenu()] = isSeparatedMenu && _isNestedSubMenu && !hasIcon,
62
+ _c[jsStyles.captionSubItemSeparatedMenuTopLevel()] = isSeparatedMenu && !isNestedSubMenu && _isSubMenu && !hasIcon,
63
+ _c[jsStyles.captionNestedItemSeparatedMenu()] = isSeparatedMenu && isNestedSubMenu && !hasIcon,
63
64
  _c[jsStyles.captionWithoutItemIcon()] = !hasIcon && !isSeparatedMenu,
64
65
  _c[jsStyles.captionSubItemWithoutColumnIcons()] = _isSubMenu && isSeparatedMenu && !hasSubIcons,
65
66
  _c[jsStyles.captionLarge(theme)] = size === 'large',