@cloud-ru/uikit-product-site-header 1.2.2 → 1.3.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 (32) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/cjs/components/HeaderItems/HeaderItem.js +2 -2
  3. package/dist/cjs/components/HeaderItems/types.d.ts +3 -0
  4. package/dist/cjs/helperComponents/Icon/Icon.d.ts +15 -0
  5. package/dist/cjs/helperComponents/Icon/Icon.js +17 -0
  6. package/dist/cjs/helperComponents/Icon/index.d.ts +1 -0
  7. package/dist/cjs/helperComponents/Icon/index.js +17 -0
  8. package/dist/cjs/helperComponents/Icon/styles.module.css +45 -0
  9. package/dist/cjs/helperComponents/LinkItemHeader/LinkItemHeader.d.ts +3 -1
  10. package/dist/cjs/helperComponents/LinkItemHeader/LinkItemHeader.js +5 -4
  11. package/dist/cjs/helperComponents/LinkItemHeader/styles.module.css +3 -0
  12. package/dist/cjs/helperComponents/MoreButton/MoreButton.js +1 -1
  13. package/dist/esm/components/HeaderItems/HeaderItem.js +2 -2
  14. package/dist/esm/components/HeaderItems/types.d.ts +3 -0
  15. package/dist/esm/helperComponents/Icon/Icon.d.ts +15 -0
  16. package/dist/esm/helperComponents/Icon/Icon.js +11 -0
  17. package/dist/esm/helperComponents/Icon/index.d.ts +1 -0
  18. package/dist/esm/helperComponents/Icon/index.js +1 -0
  19. package/dist/esm/helperComponents/Icon/styles.module.css +45 -0
  20. package/dist/esm/helperComponents/LinkItemHeader/LinkItemHeader.d.ts +3 -1
  21. package/dist/esm/helperComponents/LinkItemHeader/LinkItemHeader.js +6 -5
  22. package/dist/esm/helperComponents/LinkItemHeader/styles.module.css +3 -0
  23. package/dist/esm/helperComponents/MoreButton/MoreButton.js +1 -1
  24. package/package.json +2 -2
  25. package/src/components/HeaderItems/HeaderItem.tsx +2 -0
  26. package/src/components/HeaderItems/types.ts +4 -0
  27. package/src/helperComponents/Icon/Icon.tsx +31 -0
  28. package/src/helperComponents/Icon/index.ts +1 -0
  29. package/src/helperComponents/Icon/styles.module.scss +56 -0
  30. package/src/helperComponents/LinkItemHeader/LinkItemHeader.tsx +5 -1
  31. package/src/helperComponents/LinkItemHeader/styles.module.scss +3 -0
  32. package/src/helperComponents/MoreButton/MoreButton.tsx +1 -0
package/CHANGELOG.md CHANGED
@@ -3,6 +3,17 @@
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
+ # 1.3.0 (2026-02-17)
7
+
8
+
9
+ ### Features
10
+
11
+ * **SITE-10702:** add icon for header menu items ([e4b57e1](https://github.com/cloud-ru-tech/uikit-product/commit/e4b57e19cd9d0647f158a4431d46c9cb83fa958f))
12
+
13
+
14
+
15
+
16
+
6
17
  ## 1.2.2 (2026-02-16)
7
18
 
8
19
 
@@ -68,7 +68,7 @@ function HeaderItems({ linkItems, isMobileTabletView, activeLinkItemId }) {
68
68
  if (!linkItems || isMobileTabletView)
69
69
  return null;
70
70
  const isVisibleEmpty = visibleItems.length === 0;
71
- return ((0, jsx_runtime_1.jsxs)("div", { className: styles_module_scss_1.default.wrapper, children: [(0, jsx_runtime_1.jsx)("div", { className: (0, classnames_1.default)(styles_module_scss_1.default.linkItemsContainer, styles_module_scss_1.default.hiddenRow), ref: hiddenRowElementRef, children: linkItems.map((linkItem, index) => ((0, jsx_runtime_1.jsx)("div", Object.assign({ className: (0, classnames_1.default)(styles_module_scss_1.default.lastItemContainer, linkItem.className), ref: setItemElement(linkItem, index) }, linkItem.dataAttributes, { children: (0, jsx_runtime_1.jsx)(helperComponents_1.LinkItemHeader, { label: linkItem.label, target: linkItem.target, href: linkItem.href, onClick: linkItem.onClick }) }), linkItem.id))) }), (0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)(styles_module_scss_1.default.linkItemsContainer, {
71
+ return ((0, jsx_runtime_1.jsxs)("div", { className: styles_module_scss_1.default.wrapper, children: [(0, jsx_runtime_1.jsx)("div", { className: (0, classnames_1.default)(styles_module_scss_1.default.linkItemsContainer, styles_module_scss_1.default.hiddenRow), ref: hiddenRowElementRef, children: linkItems.map((linkItem, index) => ((0, jsx_runtime_1.jsx)("div", Object.assign({ className: (0, classnames_1.default)(styles_module_scss_1.default.lastItemContainer, linkItem.className), ref: setItemElement(linkItem, index) }, linkItem.dataAttributes, { children: (0, jsx_runtime_1.jsx)(helperComponents_1.LinkItemHeader, { label: linkItem.label, target: linkItem.target, href: linkItem.href, onClick: linkItem.onClick, icon: linkItem.icon }) }), linkItem.id))) }), (0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)(styles_module_scss_1.default.linkItemsContainer, {
72
72
  [styles_module_scss_1.default.linkItemsFirstViewContainer]: isVisibleEmpty,
73
- }), children: [(isVisibleEmpty ? linkItems : visibleItems).map(linkItem => ((0, jsx_runtime_1.jsx)("div", Object.assign({ className: (0, classnames_1.default)(styles_module_scss_1.default.lastItemContainer, linkItem.className) }, linkItem.dataAttributes, { children: (0, jsx_runtime_1.jsx)(helperComponents_1.LinkItemHeader, { label: linkItem.label, href: linkItem.href, onClick: linkItem.onClick, active: activeLinkItemId === linkItem.id }) }), linkItem.id))), hiddenItems.length > 0 && (0, jsx_runtime_1.jsx)(helperComponents_1.MoreButton, { linkItemsArray: hiddenItems, activeItemId: activeLinkItemId })] })] }));
73
+ }), children: [(isVisibleEmpty ? linkItems : visibleItems).map(linkItem => ((0, jsx_runtime_1.jsx)("div", Object.assign({ className: (0, classnames_1.default)(styles_module_scss_1.default.lastItemContainer, linkItem.className) }, linkItem.dataAttributes, { children: (0, jsx_runtime_1.jsx)(helperComponents_1.LinkItemHeader, { label: linkItem.label, href: linkItem.href, onClick: linkItem.onClick, active: activeLinkItemId === linkItem.id, icon: linkItem.icon }) }), linkItem.id))), hiddenItems.length > 0 && (0, jsx_runtime_1.jsx)(helperComponents_1.MoreButton, { linkItemsArray: hiddenItems, activeItemId: activeLinkItemId })] })] }));
74
74
  }
@@ -1,3 +1,4 @@
1
+ import { IconProps } from '../../helperComponents/Icon';
1
2
  export type LinkItem = {
2
3
  /** id Элемента */
3
4
  id: string;
@@ -15,4 +16,6 @@ export type LinkItem = {
15
16
  dataAttributes?: {
16
17
  [key: string]: string;
17
18
  };
19
+ /** Иконка */
20
+ icon?: IconProps['icon'] | null;
18
21
  };
@@ -0,0 +1,15 @@
1
+ import { JSXElementConstructor, ReactNode } from 'react';
2
+ export type IconElement = JSXElementConstructor<{
3
+ size?: number;
4
+ className?: string;
5
+ }>;
6
+ export type IconProps = {
7
+ icon: ReactNode | IconElement | {
8
+ src: string;
9
+ alt?: string;
10
+ };
11
+ size: 's' | 'm' | 'l';
12
+ 'data-test-id'?: string;
13
+ decor?: boolean;
14
+ };
15
+ export declare function Icon({ icon: Icon, size, 'data-test-id': dataTestId, decor }: IconProps): string | number | boolean | Iterable<ReactNode> | import("react/jsx-runtime").JSX.Element | null | undefined;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.Icon = Icon;
7
+ const jsx_runtime_1 = require("react/jsx-runtime");
8
+ const styles_module_scss_1 = __importDefault(require('./styles.module.css'));
9
+ const isElementConstructor = (icon) => typeof icon === 'object' && icon !== null && 'render' in icon;
10
+ function Icon({ icon: Icon, size = 'm', 'data-test-id': dataTestId, decor }) {
11
+ const isIcon = isElementConstructor(Icon);
12
+ const isImg = !isIcon && typeof Icon === 'object' && Icon !== null && 'src' in Icon;
13
+ if (isIcon || isImg) {
14
+ return ((0, jsx_runtime_1.jsxs)("div", { className: styles_module_scss_1.default.icon, "data-size": size, "data-test-id": dataTestId, "data-decor": decor || undefined, children: [isIcon && (0, jsx_runtime_1.jsx)(Icon, {}), isImg && (0, jsx_runtime_1.jsx)("img", { src: Icon.src, alt: Icon.alt })] }));
15
+ }
16
+ return Icon;
17
+ }
@@ -0,0 +1 @@
1
+ export * from './Icon';
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./Icon"), exports);
@@ -0,0 +1,45 @@
1
+ .icon{
2
+ flex-shrink:0;
3
+ color:var(--sys-graphite-text-main, #222222);
4
+ position:relative;
5
+ }
6
+ .icon svg,
7
+ .icon img{
8
+ width:100% !important;
9
+ height:100% !important;
10
+ }
11
+ .icon[data-decor]{
12
+ padding:8px;
13
+ }
14
+ .icon[data-decor] svg,
15
+ .icon[data-decor] img{
16
+ position:absolute;
17
+ top:8px;
18
+ left:8px;
19
+ width:calc(100% - 2 * 8px) !important;
20
+ height:calc(100% - 2 * 8px) !important;
21
+ }
22
+ .icon[data-decor]:before{
23
+ position:absolute;
24
+ top:0;
25
+ left:0;
26
+ content:"";
27
+ display:block;
28
+ width:100%;
29
+ height:100%;
30
+ opacity:50%;
31
+ background-color:var(--sys-graphite-decor-default, #ececec);
32
+ border-radius:var(--radius-icon-predefined-decor-square-m, 4px);
33
+ }
34
+ .icon[data-size=s]{
35
+ height:16px;
36
+ width:16px;
37
+ }
38
+ .icon[data-size=m]{
39
+ height:24px;
40
+ width:24px;
41
+ }
42
+ .icon[data-size=l]{
43
+ height:48px;
44
+ width:48px;
45
+ }
@@ -1,3 +1,4 @@
1
+ import { IconProps } from '../Icon';
1
2
  type LinkItemHeaderProps = {
2
3
  href?: string;
3
4
  target?: string;
@@ -5,6 +6,7 @@ type LinkItemHeaderProps = {
5
6
  withoutHover?: boolean;
6
7
  active?: boolean;
7
8
  onClick?: () => void;
9
+ icon?: IconProps['icon'] | null;
8
10
  };
9
- export declare function LinkItemHeader({ href, label, onClick, withoutHover, target, active }: LinkItemHeaderProps): import("react/jsx-runtime").JSX.Element;
11
+ export declare function LinkItemHeader({ href, label, onClick, withoutHover, target, active, icon }: LinkItemHeaderProps): import("react/jsx-runtime").JSX.Element;
10
12
  export {};
@@ -7,13 +7,14 @@ exports.LinkItemHeader = LinkItemHeader;
7
7
  const jsx_runtime_1 = require("react/jsx-runtime");
8
8
  const classnames_1 = __importDefault(require("classnames"));
9
9
  const typography_1 = require("@snack-uikit/typography");
10
+ const Icon_1 = require("../Icon");
10
11
  const styles_module_scss_1 = __importDefault(require('./styles.module.css'));
11
- function LinkItemHeader({ href, label, onClick, withoutHover, target, active }) {
12
+ function LinkItemHeader({ href, label, onClick, withoutHover, target, active, icon }) {
12
13
  if (href) {
13
- return ((0, jsx_runtime_1.jsx)("a", { href: href, target: target, onClick: onClick, className: styles_module_scss_1.default.item, children: (0, jsx_runtime_1.jsx)(typography_1.Typography.SansTitleS, { children: label }) }));
14
+ return ((0, jsx_runtime_1.jsxs)("a", { href: href, target: target, onClick: onClick, className: styles_module_scss_1.default.item, children: [(0, jsx_runtime_1.jsx)(typography_1.Typography.SansTitleS, { children: label }), icon && (0, jsx_runtime_1.jsx)(Icon_1.Icon, { icon: icon, size: 's' })] }));
14
15
  }
15
- return ((0, jsx_runtime_1.jsx)("button", { onClick: onClick, className: (0, classnames_1.default)(styles_module_scss_1.default.item, styles_module_scss_1.default.button, {
16
+ return ((0, jsx_runtime_1.jsxs)("button", { onClick: onClick, className: (0, classnames_1.default)(styles_module_scss_1.default.item, styles_module_scss_1.default.button, {
16
17
  [styles_module_scss_1.default.active]: active,
17
18
  [styles_module_scss_1.default.hovered]: !withoutHover && !active,
18
- }), children: (0, jsx_runtime_1.jsx)(typography_1.Typography.SansTitleS, { children: label }) }));
19
+ }), children: [(0, jsx_runtime_1.jsx)(typography_1.Typography.SansTitleS, { children: label }), icon && (0, jsx_runtime_1.jsx)(Icon_1.Icon, { icon: icon, size: 's' })] }));
19
20
  }
@@ -14,6 +14,9 @@
14
14
  color:var(--sys-graphite-accent-default, #222222);
15
15
  transition:color 0.3s ease-in-out;
16
16
  cursor:pointer;
17
+ display:flex;
18
+ align-items:center;
19
+ gap:var(--dimension-050m, 4px);
17
20
  }
18
21
  .item:hover{
19
22
  color:var(--sys-graphite-accent-hovered, #383838);
@@ -25,5 +25,5 @@ function MoreButton({ linkItemsArray, activeItemId }) {
25
25
  }, item.className) }, item.dataAttributes, { children: (0, jsx_runtime_1.jsx)(LinkItemHeader_1.LinkItemHeader, { label: item.label, onClick: () => {
26
26
  item.onClick && item.onClick();
27
27
  onClickOpen();
28
- }, href: item.href, withoutHover: true }) }), item.id))) }), children: (0, jsx_runtime_1.jsx)("button", { className: styles_module_scss_1.default.button, onClick: onClickOpen, children: (0, jsx_runtime_1.jsx)(uikit_product_icons_1.MoreSVG, {}) }) }));
28
+ }, href: item.href, icon: item.icon, withoutHover: true }) }), item.id))) }), children: (0, jsx_runtime_1.jsx)("button", { className: styles_module_scss_1.default.button, onClick: onClickOpen, children: (0, jsx_runtime_1.jsx)(uikit_product_icons_1.MoreSVG, {}) }) }));
29
29
  }
@@ -62,7 +62,7 @@ export function HeaderItems({ linkItems, isMobileTabletView, activeLinkItemId })
62
62
  if (!linkItems || isMobileTabletView)
63
63
  return null;
64
64
  const isVisibleEmpty = visibleItems.length === 0;
65
- return (_jsxs("div", { className: styles.wrapper, children: [_jsx("div", { className: cn(styles.linkItemsContainer, styles.hiddenRow), ref: hiddenRowElementRef, children: linkItems.map((linkItem, index) => (_jsx("div", Object.assign({ className: cn(styles.lastItemContainer, linkItem.className), ref: setItemElement(linkItem, index) }, linkItem.dataAttributes, { children: _jsx(LinkItemHeader, { label: linkItem.label, target: linkItem.target, href: linkItem.href, onClick: linkItem.onClick }) }), linkItem.id))) }), _jsxs("div", { className: cn(styles.linkItemsContainer, {
65
+ return (_jsxs("div", { className: styles.wrapper, children: [_jsx("div", { className: cn(styles.linkItemsContainer, styles.hiddenRow), ref: hiddenRowElementRef, children: linkItems.map((linkItem, index) => (_jsx("div", Object.assign({ className: cn(styles.lastItemContainer, linkItem.className), ref: setItemElement(linkItem, index) }, linkItem.dataAttributes, { children: _jsx(LinkItemHeader, { label: linkItem.label, target: linkItem.target, href: linkItem.href, onClick: linkItem.onClick, icon: linkItem.icon }) }), linkItem.id))) }), _jsxs("div", { className: cn(styles.linkItemsContainer, {
66
66
  [styles.linkItemsFirstViewContainer]: isVisibleEmpty,
67
- }), children: [(isVisibleEmpty ? linkItems : visibleItems).map(linkItem => (_jsx("div", Object.assign({ className: cn(styles.lastItemContainer, linkItem.className) }, linkItem.dataAttributes, { children: _jsx(LinkItemHeader, { label: linkItem.label, href: linkItem.href, onClick: linkItem.onClick, active: activeLinkItemId === linkItem.id }) }), linkItem.id))), hiddenItems.length > 0 && _jsx(MoreButton, { linkItemsArray: hiddenItems, activeItemId: activeLinkItemId })] })] }));
67
+ }), children: [(isVisibleEmpty ? linkItems : visibleItems).map(linkItem => (_jsx("div", Object.assign({ className: cn(styles.lastItemContainer, linkItem.className) }, linkItem.dataAttributes, { children: _jsx(LinkItemHeader, { label: linkItem.label, href: linkItem.href, onClick: linkItem.onClick, active: activeLinkItemId === linkItem.id, icon: linkItem.icon }) }), linkItem.id))), hiddenItems.length > 0 && _jsx(MoreButton, { linkItemsArray: hiddenItems, activeItemId: activeLinkItemId })] })] }));
68
68
  }
@@ -1,3 +1,4 @@
1
+ import { IconProps } from '../../helperComponents/Icon';
1
2
  export type LinkItem = {
2
3
  /** id Элемента */
3
4
  id: string;
@@ -15,4 +16,6 @@ export type LinkItem = {
15
16
  dataAttributes?: {
16
17
  [key: string]: string;
17
18
  };
19
+ /** Иконка */
20
+ icon?: IconProps['icon'] | null;
18
21
  };
@@ -0,0 +1,15 @@
1
+ import { JSXElementConstructor, ReactNode } from 'react';
2
+ export type IconElement = JSXElementConstructor<{
3
+ size?: number;
4
+ className?: string;
5
+ }>;
6
+ export type IconProps = {
7
+ icon: ReactNode | IconElement | {
8
+ src: string;
9
+ alt?: string;
10
+ };
11
+ size: 's' | 'm' | 'l';
12
+ 'data-test-id'?: string;
13
+ decor?: boolean;
14
+ };
15
+ export declare function Icon({ icon: Icon, size, 'data-test-id': dataTestId, decor }: IconProps): string | number | boolean | Iterable<ReactNode> | import("react/jsx-runtime").JSX.Element | null | undefined;
@@ -0,0 +1,11 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import styles from './styles.module.css';
3
+ const isElementConstructor = (icon) => typeof icon === 'object' && icon !== null && 'render' in icon;
4
+ export function Icon({ icon: Icon, size = 'm', 'data-test-id': dataTestId, decor }) {
5
+ const isIcon = isElementConstructor(Icon);
6
+ const isImg = !isIcon && typeof Icon === 'object' && Icon !== null && 'src' in Icon;
7
+ if (isIcon || isImg) {
8
+ return (_jsxs("div", { className: styles.icon, "data-size": size, "data-test-id": dataTestId, "data-decor": decor || undefined, children: [isIcon && _jsx(Icon, {}), isImg && _jsx("img", { src: Icon.src, alt: Icon.alt })] }));
9
+ }
10
+ return Icon;
11
+ }
@@ -0,0 +1 @@
1
+ export * from './Icon';
@@ -0,0 +1 @@
1
+ export * from './Icon';
@@ -0,0 +1,45 @@
1
+ .icon{
2
+ flex-shrink:0;
3
+ color:var(--sys-graphite-text-main, #222222);
4
+ position:relative;
5
+ }
6
+ .icon svg,
7
+ .icon img{
8
+ width:100% !important;
9
+ height:100% !important;
10
+ }
11
+ .icon[data-decor]{
12
+ padding:8px;
13
+ }
14
+ .icon[data-decor] svg,
15
+ .icon[data-decor] img{
16
+ position:absolute;
17
+ top:8px;
18
+ left:8px;
19
+ width:calc(100% - 2 * 8px) !important;
20
+ height:calc(100% - 2 * 8px) !important;
21
+ }
22
+ .icon[data-decor]:before{
23
+ position:absolute;
24
+ top:0;
25
+ left:0;
26
+ content:"";
27
+ display:block;
28
+ width:100%;
29
+ height:100%;
30
+ opacity:50%;
31
+ background-color:var(--sys-graphite-decor-default, #ececec);
32
+ border-radius:var(--radius-icon-predefined-decor-square-m, 4px);
33
+ }
34
+ .icon[data-size=s]{
35
+ height:16px;
36
+ width:16px;
37
+ }
38
+ .icon[data-size=m]{
39
+ height:24px;
40
+ width:24px;
41
+ }
42
+ .icon[data-size=l]{
43
+ height:48px;
44
+ width:48px;
45
+ }
@@ -1,3 +1,4 @@
1
+ import { IconProps } from '../Icon';
1
2
  type LinkItemHeaderProps = {
2
3
  href?: string;
3
4
  target?: string;
@@ -5,6 +6,7 @@ type LinkItemHeaderProps = {
5
6
  withoutHover?: boolean;
6
7
  active?: boolean;
7
8
  onClick?: () => void;
9
+ icon?: IconProps['icon'] | null;
8
10
  };
9
- export declare function LinkItemHeader({ href, label, onClick, withoutHover, target, active }: LinkItemHeaderProps): import("react/jsx-runtime").JSX.Element;
11
+ export declare function LinkItemHeader({ href, label, onClick, withoutHover, target, active, icon }: LinkItemHeaderProps): import("react/jsx-runtime").JSX.Element;
10
12
  export {};
@@ -1,13 +1,14 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import cn from 'classnames';
3
3
  import { Typography } from '@snack-uikit/typography';
4
+ import { Icon } from '../Icon';
4
5
  import styles from './styles.module.css';
5
- export function LinkItemHeader({ href, label, onClick, withoutHover, target, active }) {
6
+ export function LinkItemHeader({ href, label, onClick, withoutHover, target, active, icon }) {
6
7
  if (href) {
7
- return (_jsx("a", { href: href, target: target, onClick: onClick, className: styles.item, children: _jsx(Typography.SansTitleS, { children: label }) }));
8
+ return (_jsxs("a", { href: href, target: target, onClick: onClick, className: styles.item, children: [_jsx(Typography.SansTitleS, { children: label }), icon && _jsx(Icon, { icon: icon, size: 's' })] }));
8
9
  }
9
- return (_jsx("button", { onClick: onClick, className: cn(styles.item, styles.button, {
10
+ return (_jsxs("button", { onClick: onClick, className: cn(styles.item, styles.button, {
10
11
  [styles.active]: active,
11
12
  [styles.hovered]: !withoutHover && !active,
12
- }), children: _jsx(Typography.SansTitleS, { children: label }) }));
13
+ }), children: [_jsx(Typography.SansTitleS, { children: label }), icon && _jsx(Icon, { icon: icon, size: 's' })] }));
13
14
  }
@@ -14,6 +14,9 @@
14
14
  color:var(--sys-graphite-accent-default, #222222);
15
15
  transition:color 0.3s ease-in-out;
16
16
  cursor:pointer;
17
+ display:flex;
18
+ align-items:center;
19
+ gap:var(--dimension-050m, 4px);
17
20
  }
18
21
  .item:hover{
19
22
  color:var(--sys-graphite-accent-hovered, #383838);
@@ -19,5 +19,5 @@ export function MoreButton({ linkItemsArray, activeItemId }) {
19
19
  }, item.className) }, item.dataAttributes, { children: _jsx(LinkItemHeader, { label: item.label, onClick: () => {
20
20
  item.onClick && item.onClick();
21
21
  onClickOpen();
22
- }, href: item.href, withoutHover: true }) }), item.id))) }), children: _jsx("button", { className: styles.button, onClick: onClickOpen, children: _jsx(MoreSVG, {}) }) }));
22
+ }, href: item.href, icon: item.icon, withoutHover: true }) }), item.id))) }), children: _jsx("button", { className: styles.button, onClick: onClickOpen, children: _jsx(MoreSVG, {}) }) }));
23
23
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cloud-ru/uikit-product-site-header",
3
3
  "title": "Siteheader",
4
- "version": "1.2.2",
4
+ "version": "1.3.0",
5
5
  "sideEffects": [
6
6
  "*.css",
7
7
  "*.woff",
@@ -52,5 +52,5 @@
52
52
  "peerDependencies": {
53
53
  "@cloud-ru/figma-tokens-web": "*"
54
54
  },
55
- "gitHead": "2c5f4aadeb5beac7a522f3183a7250dc20d6f9a9"
55
+ "gitHead": "8e8439e29e7ea98e2a1ca8f02c39f7ac50f4e156"
56
56
  }
@@ -101,6 +101,7 @@ export function HeaderItems({ linkItems, isMobileTabletView, activeLinkItemId }:
101
101
  target={linkItem.target}
102
102
  href={linkItem.href}
103
103
  onClick={linkItem.onClick}
104
+ icon={linkItem.icon}
104
105
  />
105
106
  </div>
106
107
  ))}
@@ -122,6 +123,7 @@ export function HeaderItems({ linkItems, isMobileTabletView, activeLinkItemId }:
122
123
  href={linkItem.href}
123
124
  onClick={linkItem.onClick}
124
125
  active={activeLinkItemId === linkItem.id}
126
+ icon={linkItem.icon}
125
127
  />
126
128
  </div>
127
129
  ))}
@@ -1,3 +1,5 @@
1
+ import { IconProps } from '../../helperComponents/Icon';
2
+
1
3
  export type LinkItem = {
2
4
  /** id Элемента */
3
5
  id: string;
@@ -15,4 +17,6 @@ export type LinkItem = {
15
17
  dataAttributes?: {
16
18
  [key: string]: string;
17
19
  };
20
+ /** Иконка */
21
+ icon?: IconProps['icon'] | null;
18
22
  };
@@ -0,0 +1,31 @@
1
+ import { JSXElementConstructor, ReactNode } from 'react';
2
+
3
+ import styles from './styles.module.scss';
4
+
5
+ export type IconElement = JSXElementConstructor<{ size?: number; className?: string }>;
6
+
7
+ export type IconProps = {
8
+ icon: ReactNode | IconElement | { src: string; alt?: string };
9
+ size: 's' | 'm' | 'l';
10
+ 'data-test-id'?: string;
11
+ decor?: boolean;
12
+ };
13
+
14
+ const isElementConstructor = (icon: IconProps['icon']): icon is IconElement =>
15
+ typeof icon === 'object' && icon !== null && 'render' in icon;
16
+
17
+ export function Icon({ icon: Icon, size = 'm', 'data-test-id': dataTestId, decor }: IconProps) {
18
+ const isIcon = isElementConstructor(Icon);
19
+ const isImg = !isIcon && typeof Icon === 'object' && Icon !== null && 'src' in Icon;
20
+
21
+ if (isIcon || isImg) {
22
+ return (
23
+ <div className={styles.icon} data-size={size} data-test-id={dataTestId} data-decor={decor || undefined}>
24
+ {isIcon && <Icon />}
25
+ {isImg && <img src={Icon.src} alt={Icon.alt} />}
26
+ </div>
27
+ );
28
+ }
29
+
30
+ return Icon as ReactNode;
31
+ }
@@ -0,0 +1 @@
1
+ export * from './Icon';
@@ -0,0 +1,56 @@
1
+ @use '@cloud-ru/figma-tokens-web/build/scss/components/styles-tokens-element' as ste;
2
+
3
+ $decor-padding: 8px;
4
+
5
+ .icon {
6
+ flex-shrink: 0;
7
+ color: ste.$sys-graphite-text-main;
8
+ position: relative;
9
+
10
+ svg,
11
+ img {
12
+ width: 100% !important; /* stylelint-disable-line declaration-no-important */
13
+ height: 100% !important; /* stylelint-disable-line declaration-no-important */
14
+ }
15
+
16
+ &[data-decor] {
17
+ padding: $decor-padding;
18
+
19
+ & svg,
20
+ img {
21
+ position: absolute;
22
+ top: 8px;
23
+ left: 8px;
24
+ width: calc(100% - 2 * #{$decor-padding}) !important; /* stylelint-disable-line declaration-no-important */
25
+ height: calc(100% - 2 * #{$decor-padding}) !important; /* stylelint-disable-line declaration-no-important */
26
+ }
27
+
28
+ &:before {
29
+ position: absolute;
30
+ top: 0;
31
+ left: 0;
32
+ content: '';
33
+ display: block;
34
+ width: 100%;
35
+ height: 100%;
36
+ opacity: 50%;
37
+ background-color: ste.$sys-graphite-decor-default;
38
+ border-radius: ste.$radius-icon-predefined-decor-square-m;
39
+ }
40
+ }
41
+
42
+ &[data-size='s'] {
43
+ height: 16px;
44
+ width: 16px;
45
+ }
46
+
47
+ &[data-size='m'] {
48
+ height: 24px;
49
+ width: 24px;
50
+ }
51
+
52
+ &[data-size='l'] {
53
+ height: 48px;
54
+ width: 48px;
55
+ }
56
+ }
@@ -2,6 +2,7 @@ import cn from 'classnames';
2
2
 
3
3
  import { Typography } from '@snack-uikit/typography';
4
4
 
5
+ import { Icon, IconProps } from '../Icon';
5
6
  import styles from './styles.module.scss';
6
7
 
7
8
  type LinkItemHeaderProps = {
@@ -11,13 +12,15 @@ type LinkItemHeaderProps = {
11
12
  withoutHover?: boolean;
12
13
  active?: boolean;
13
14
  onClick?: () => void;
15
+ icon?: IconProps['icon'] | null;
14
16
  };
15
17
 
16
- export function LinkItemHeader({ href, label, onClick, withoutHover, target, active }: LinkItemHeaderProps) {
18
+ export function LinkItemHeader({ href, label, onClick, withoutHover, target, active, icon }: LinkItemHeaderProps) {
17
19
  if (href) {
18
20
  return (
19
21
  <a href={href} target={target} onClick={onClick} className={styles.item}>
20
22
  <Typography.SansTitleS>{label}</Typography.SansTitleS>
23
+ {icon && <Icon icon={icon} size='s' />}
21
24
  </a>
22
25
  );
23
26
  }
@@ -31,6 +34,7 @@ export function LinkItemHeader({ href, label, onClick, withoutHover, target, act
31
34
  })}
32
35
  >
33
36
  <Typography.SansTitleS>{label}</Typography.SansTitleS>
37
+ {icon && <Icon icon={icon} size='s' />}
34
38
  </button>
35
39
  );
36
40
  }
@@ -18,6 +18,9 @@
18
18
  color: ste.$sys-graphite-accent-default;
19
19
  transition: color 0.3s ease-in-out;
20
20
  cursor: pointer;
21
+ display: flex;
22
+ align-items: center;
23
+ gap: ste.$dimension-050m;
21
24
 
22
25
  &:hover {
23
26
  color: ste.$sys-graphite-accent-hovered;
@@ -49,6 +49,7 @@ export function MoreButton({ linkItemsArray, activeItemId }: MoreButtonProps) {
49
49
  onClickOpen();
50
50
  }}
51
51
  href={item.href}
52
+ icon={item.icon}
52
53
  withoutHover
53
54
  />
54
55
  </div>