@cloud-ru/ds-uikit-product-header 1.3.9 → 1.3.10-preview-1030ded1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -2
- package/dist/cjs/components/MainMenu/helperComponents/Banners/MenuBanner.d.ts +1 -1
- package/dist/cjs/components/MainMenu/helperComponents/Banners/MenuBanner.js +3 -2
- package/dist/cjs/components/MainMenu/helperComponents/Banners/styles.module.css +11 -15
- package/dist/cjs/components/MainMenu/helperComponents/Content/Content.js +0 -5
- package/dist/cjs/components/MainMenu/helperComponents/Content/helperComponents/SortableGroup/components/SortableGroupCards.js +1 -1
- package/dist/cjs/components/MainMenu/helperComponents/Content/helperComponents/SortableGroup/components/SubCategory/SubCategory.js +16 -2
- package/dist/cjs/components/MainMenu/helperComponents/Content/helperComponents/SortableGroup/components/SubCategory/styles.module.css +7 -1
- package/dist/cjs/components/MainMenu/helperComponents/Content/helperComponents/SortableGroup/styles.module.css +3 -0
- package/dist/cjs/components/MainMenu/helperComponents/Favorites/styles.module.css +2 -2
- package/dist/cjs/components/MainMenu/helperComponents/ServiceCard/ServiceCard.js +0 -3
- package/dist/cjs/components/MainMenu/types.d.ts +14 -3
- package/dist/cjs/components/MainMenu/utils/innerLink.d.ts +10 -0
- package/dist/cjs/components/MainMenu/utils/innerLink.js +20 -0
- package/dist/cjs/style.css +23 -18
- package/dist/esm/components/MainMenu/helperComponents/Banners/MenuBanner.d.ts +1 -1
- package/dist/esm/components/MainMenu/helperComponents/Banners/MenuBanner.js +3 -2
- package/dist/esm/components/MainMenu/helperComponents/Banners/styles.module.css +11 -15
- package/dist/esm/components/MainMenu/helperComponents/Content/Content.js +1 -6
- package/dist/esm/components/MainMenu/helperComponents/Content/helperComponents/SortableGroup/components/SortableGroupCards.js +2 -2
- package/dist/esm/components/MainMenu/helperComponents/Content/helperComponents/SortableGroup/components/SubCategory/SubCategory.js +17 -3
- package/dist/esm/components/MainMenu/helperComponents/Content/helperComponents/SortableGroup/components/SubCategory/styles.module.css +7 -1
- package/dist/esm/components/MainMenu/helperComponents/Content/helperComponents/SortableGroup/styles.module.css +3 -0
- package/dist/esm/components/MainMenu/helperComponents/Favorites/styles.module.css +2 -2
- package/dist/esm/components/MainMenu/helperComponents/ServiceCard/ServiceCard.js +0 -3
- package/dist/esm/components/MainMenu/types.d.ts +14 -3
- package/dist/esm/components/MainMenu/utils/innerLink.d.ts +10 -0
- package/dist/esm/components/MainMenu/utils/innerLink.js +19 -0
- package/dist/esm/style.css +23 -18
- package/dist/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/tsconfig.esm.tsbuildinfo +1 -1
- package/package.json +28 -27
- package/src/components/MainMenu/helperComponents/Banners/MenuBanner.tsx +44 -42
- package/src/components/MainMenu/helperComponents/Banners/styles.module.scss +15 -22
- package/src/components/MainMenu/helperComponents/Content/Content.tsx +1 -7
- package/src/components/MainMenu/helperComponents/Content/helperComponents/SortableGroup/components/SortableGroupCards.tsx +2 -2
- package/src/components/MainMenu/helperComponents/Content/helperComponents/SortableGroup/components/SubCategory/SubCategory.tsx +61 -2
- package/src/components/MainMenu/helperComponents/Content/helperComponents/SortableGroup/components/SubCategory/styles.module.scss +10 -1
- package/src/components/MainMenu/helperComponents/Content/helperComponents/SortableGroup/styles.module.scss +5 -0
- package/src/components/MainMenu/helperComponents/Favorites/styles.module.scss +3 -2
- package/src/components/MainMenu/helperComponents/ServiceCard/ServiceCard.tsx +0 -4
- package/src/components/MainMenu/types.ts +15 -3
- package/src/components/MainMenu/utils/innerLink.ts +23 -0
package/README.md
CHANGED
|
@@ -342,7 +342,6 @@ function LocalMainMenu() {
|
|
|
342
342
|
| `badge` | `CardServiceLightProps` \| `PromoTagPredefinedBaseProps` | — | |
|
|
343
343
|
| `description` | `string \| undefined` | — | Краткое описание сервиса — отображается при включённом переключателе «Описание». |
|
|
344
344
|
| `disabled` | `boolean \| undefined` | — | |
|
|
345
|
-
| `expandableEnabled` | `boolean \| undefined` | — | Разрешено ли раскрытие карточки. default=false - Запрещено |
|
|
346
345
|
| `favoritesEnabled` | `boolean \| undefined` | — | Разрешено ли добавление карточки в избранное. default=true - разрешено |
|
|
347
346
|
| `hidden` | `boolean \| undefined` | — | |
|
|
348
347
|
| `href` | `string \| undefined` | — | |
|
|
@@ -351,6 +350,9 @@ function LocalMainMenu() {
|
|
|
351
350
|
| `items` | `InnerLink` | — | Вложенные сервисы подкатегории. <br/> При наличии карточка раскрывается аккордеоном: в свёрнутом виде — обычная карточка <br/> с кнопкой раскрытия, в развёрнутом — заголовок <br/> {@link <br/> TitleClickable <br/> } <br/> и сетка вложенных сервисов. |
|
|
352
351
|
| `label` | `string` | — | Заголовок карточки. |
|
|
353
352
|
| `onClick` | `(e?: MouseEvent<HTMLElement>) => void` | — | |
|
|
353
|
+
| `viewMode` | `"expandable"` \| `"expanded"` \| `"flat-link"` \| `"group-title-only"` | — | Режим отображения карточки. default='expandable'. <br/> - `'expandable'` — подкатегория при наличии реальных <br/> {@link <br/> items <br/> } <br/> : заголовок <br/> {@link <br/> TitleClickable <br/> } <br/> с шевроном и сетка вложенных сервисов (раскрытие/схлопывание — <br/> см. <br/> {@link <br/> expandableEnabled <br/> } <br/> ). Без `items` — обычная карточка сервиса. <br/> - `'group-title-only'` — заголовок подкатегории ( <br/> {@link <br/> TitleClickable <br/> } <br/> с шевроном) без <br/> раскрываемого тела, даже если `items` заданы: карточка ведёт себя как обычная ссылка. <br/> Полезно для группы, чьи вложенные сервисы показываются на отдельной странице. <br/> - `'flat-link'` — всегда обычная карточка сервиса, даже если `items` заданы. |
|
|
354
|
+
|
|
355
|
+
- `InnerLinkViewMode` = `"expandable"` \| `"expanded"` \| `"flat-link"` \| `"group-title-only"`
|
|
354
356
|
|
|
355
357
|
**LinksGroup**
|
|
356
358
|
|
|
@@ -514,7 +516,6 @@ import { MainMenu, MenuMobile } from '@cloud-ru/ds-uikit-product-header';
|
|
|
514
516
|
| `badge` | `CardServiceLightProps` \| `PromoTagPredefinedBaseProps` | — | |
|
|
515
517
|
| `description` | `string \| undefined` | — | Краткое описание сервиса — отображается при включённом переключателе «Описание». |
|
|
516
518
|
| `disabled` | `boolean \| undefined` | — | |
|
|
517
|
-
| `expandableEnabled` | `boolean \| undefined` | — | Разрешено ли раскрытие карточки. default=false - Запрещено |
|
|
518
519
|
| `favoritesEnabled` | `boolean \| undefined` | — | Разрешено ли добавление карточки в избранное. default=true - разрешено |
|
|
519
520
|
| `hidden` | `boolean \| undefined` | — | |
|
|
520
521
|
| `href` | `string \| undefined` | — | |
|
|
@@ -523,6 +524,9 @@ import { MainMenu, MenuMobile } from '@cloud-ru/ds-uikit-product-header';
|
|
|
523
524
|
| `items` | `InnerLink` | — | Вложенные сервисы подкатегории. <br/> При наличии карточка раскрывается аккордеоном: в свёрнутом виде — обычная карточка <br/> с кнопкой раскрытия, в развёрнутом — заголовок <br/> {@link <br/> TitleClickable <br/> } <br/> и сетка вложенных сервисов. |
|
|
524
525
|
| `label` | `string` | — | Заголовок карточки. |
|
|
525
526
|
| `onClick` | `(e?: MouseEvent<HTMLElement>) => void` | — | |
|
|
527
|
+
| `viewMode` | `"expandable"` \| `"expanded"` \| `"flat-link"` \| `"group-title-only"` | — | Режим отображения карточки. default='expandable'. <br/> - `'expandable'` — подкатегория при наличии реальных <br/> {@link <br/> items <br/> } <br/> : заголовок <br/> {@link <br/> TitleClickable <br/> } <br/> с шевроном и сетка вложенных сервисов (раскрытие/схлопывание — <br/> см. <br/> {@link <br/> expandableEnabled <br/> } <br/> ). Без `items` — обычная карточка сервиса. <br/> - `'group-title-only'` — заголовок подкатегории ( <br/> {@link <br/> TitleClickable <br/> } <br/> с шевроном) без <br/> раскрываемого тела, даже если `items` заданы: карточка ведёт себя как обычная ссылка. <br/> Полезно для группы, чьи вложенные сервисы показываются на отдельной странице. <br/> - `'flat-link'` — всегда обычная карточка сервиса, даже если `items` заданы. |
|
|
528
|
+
|
|
529
|
+
- `InnerLinkViewMode` = `"expandable"` \| `"expanded"` \| `"flat-link"` \| `"group-title-only"`
|
|
526
530
|
|
|
527
531
|
**LinksGroup**
|
|
528
532
|
|
|
@@ -13,4 +13,4 @@ export type MenuBannerProps = WithSupportProps<{
|
|
|
13
13
|
/** CSS-класс корневого элемента */
|
|
14
14
|
className?: string;
|
|
15
15
|
} & Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'title' | 'children'>>;
|
|
16
|
-
export declare function MenuBanner({ title, promoTag, afterTitle, onClose, className, href,
|
|
16
|
+
export declare function MenuBanner({ title, promoTag, afterTitle, onClose, className, href, 'data-test-id': dataTestId, ...rest }: MenuBannerProps): ReactElement;
|
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.MenuBanner = MenuBanner;
|
|
7
7
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
8
8
|
const button_1 = require("@cloud-ru/ds-button");
|
|
9
|
+
const card_1 = require("@cloud-ru/ds-card");
|
|
9
10
|
const system_1 = require("@cloud-ru/ds-icons/interface/system");
|
|
10
11
|
const promo_tag_1 = require("@cloud-ru/ds-promo-tag");
|
|
11
12
|
const theme_1 = require("@cloud-ru/ds-theme");
|
|
@@ -15,7 +16,7 @@ const react_1 = require("react");
|
|
|
15
16
|
const locale_1 = require("../../../../locale");
|
|
16
17
|
const constants_1 = require("./constants");
|
|
17
18
|
const styles_module_scss_1 = __importDefault(require('./styles.module.css'));
|
|
18
|
-
function MenuBanner({ title, promoTag, afterTitle, onClose, className, href = '#',
|
|
19
|
+
function MenuBanner({ title, promoTag, afterTitle, onClose, className, href = '#', 'data-test-id': dataTestId, ...rest }) {
|
|
19
20
|
const { t } = locale_1.headerLocale.useTranslations();
|
|
20
21
|
const compactThemeClassname = (0, theme_1.useThemeClassnames)({ density: 'compact' });
|
|
21
22
|
const handleClose = (0, react_1.useCallback)(e => {
|
|
@@ -23,5 +24,5 @@ function MenuBanner({ title, promoTag, afterTitle, onClose, className, href = '#
|
|
|
23
24
|
e.stopPropagation();
|
|
24
25
|
onClose?.(e);
|
|
25
26
|
}, [onClose]);
|
|
26
|
-
return ((0, jsx_runtime_1.
|
|
27
|
+
return ((0, jsx_runtime_1.jsx)(card_1.Card, { as: 'a', href: href, radius: 'l', view: 'simple', className: (0, classnames_1.default)(styles_module_scss_1.default.root, className), "data-test-id": dataTestId ?? constants_1.MENU_BANNER_TEST_IDS.root, ...rest, children: (0, jsx_runtime_1.jsxs)("div", { className: styles_module_scss_1.default.contentRow, children: [(0, jsx_runtime_1.jsxs)("span", { className: styles_module_scss_1.default.titleWrapper, children: [(0, jsx_runtime_1.jsx)(typography_1.Typography, { as: 'span', variant: 'body', size: 'm', className: styles_module_scss_1.default.title, "data-test-id": constants_1.MENU_BANNER_TEST_IDS.title, children: title }), promoTag && ((0, jsx_runtime_1.jsx)(promo_tag_1.PromoTag, { ...promoTag, roleAppearance: promo_tag_1.ROLE_APPEARANCE.Decor, size: promo_tag_1.SIZE.Xs, "data-test-id": constants_1.MENU_BANNER_TEST_IDS.promoTag }))] }), afterTitle && ((0, jsx_runtime_1.jsx)("div", { className: styles_module_scss_1.default.afterTitle, "data-test-id": constants_1.MENU_BANNER_TEST_IDS.afterTitle, children: afterTitle })), onClose && ((0, jsx_runtime_1.jsx)(button_1.Button, { className: (0, classnames_1.default)(styles_module_scss_1.default.closeButton, compactThemeClassname), view: 'elevated', appearance: 'neutral', size: 's', icon: (0, jsx_runtime_1.jsx)(system_1.CrossSVG, { size: 16 }), onClick: handleClose, "aria-label": t('close'), "data-test-id": constants_1.MENU_BANNER_TEST_IDS.close }))] }) }));
|
|
27
28
|
}
|
|
@@ -10,28 +10,24 @@
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
.root{
|
|
13
|
+
width:100%;
|
|
14
|
+
min-width:0;
|
|
15
|
+
}
|
|
16
|
+
.root:hover .closeButton, .root:focus-visible .closeButton, .root:has(*:focus-visible) .closeButton{
|
|
17
|
+
visibility:visible;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.contentRow{
|
|
13
21
|
position:relative;
|
|
14
22
|
display:flex;
|
|
15
|
-
gap:var(--sn-primitive-dimension-
|
|
23
|
+
gap:var(--sn-density-spacing-interval-s, var(--sn-primitive-dimension-8, 8px));
|
|
16
24
|
align-items:center;
|
|
17
25
|
box-sizing:border-box;
|
|
18
26
|
width:100%;
|
|
19
27
|
min-width:0;
|
|
20
|
-
min-height:var(--sn-primitive-dimension-
|
|
28
|
+
min-height:var(--sn-primitive-dimension-40, 40px);
|
|
21
29
|
padding:0 var(--sn-primitive-dimension-12, 12px);
|
|
22
|
-
border-radius:
|
|
23
|
-
font:inherit;
|
|
24
|
-
color:inherit;
|
|
25
|
-
text-align:left;
|
|
26
|
-
text-decoration:none;
|
|
27
|
-
background-color:var(--sn-theme-color-neutral-background1Level, var(--sn-brand-color-neutral-95, var(--sn-primitive-color-gray-95, #fdfdfd)));
|
|
28
|
-
}
|
|
29
|
-
.root:hover .closeButton, .root:focus-visible .closeButton, .root:focus-within .closeButton{
|
|
30
|
-
visibility:visible;
|
|
31
|
-
}
|
|
32
|
-
.root:focus-visible{
|
|
33
|
-
outline:var(--sn-theme-color-available-complementary, #000000) solid var(--sn-primitive-strokeWeight-strokeSemiBold, 2px);
|
|
34
|
-
outline-offset:var(--sn-primitive-strokeWeight-strokeSemiBold, 2px);
|
|
30
|
+
border-radius:inherit;
|
|
35
31
|
}
|
|
36
32
|
|
|
37
33
|
.titleWrapper{
|
|
@@ -33,11 +33,6 @@ function Content({ searchValue, search, rightTop, segments, searchGroups = [], s
|
|
|
33
33
|
});
|
|
34
34
|
const isSearching = Boolean(searchValue);
|
|
35
35
|
const enableServiceDrag = Boolean(favorite) && !isMobile && !isSearching;
|
|
36
|
-
(0, react_1.useEffect)(() => {
|
|
37
|
-
if (!segments?.some(segment => segment.id === segmentId) && defaultSegmentId) {
|
|
38
|
-
setSegmentId(defaultSegmentId);
|
|
39
|
-
}
|
|
40
|
-
}, [defaultSegmentId, segmentId, setSegmentId, segments]);
|
|
41
36
|
const handleLinkClick = (0, react_1.useCallback)((service, e) => {
|
|
42
37
|
if (service.disabled) {
|
|
43
38
|
e?.preventDefault();
|
|
@@ -15,7 +15,7 @@ function SortableGroupCards({ groupId, items, showDescription, isMobile, enableS
|
|
|
15
15
|
return null;
|
|
16
16
|
}
|
|
17
17
|
const key = String(groupId) + service.id;
|
|
18
|
-
if ((0, innerLink_1.
|
|
18
|
+
if ((0, innerLink_1.isSubCategoryCard)(service)) {
|
|
19
19
|
return ((0, jsx_runtime_1.jsx)(SubCategory_1.SubCategory, { groupId: groupId, service: service, showDescription: showDescription, isMobile: isMobile, dragDisabled: !enableServiceDrag, favorite: favorite, groupFavoritesEnabled: groupFavoritesEnabled, onServiceClick: onServiceClick }, key));
|
|
20
20
|
}
|
|
21
21
|
return ((0, jsx_runtime_1.jsx)(ServiceCard_1.DraggableServiceCard, { groupId: groupId, service: service, favorite: favorite, isMobile: isMobile, onServiceClick: onServiceClick, showDescription: showDescription, dragDisabled: !enableServiceDrag }, key));
|
|
@@ -13,18 +13,32 @@ const constants_1 = require("../../../../constants");
|
|
|
13
13
|
const styles_module_scss_1 = __importDefault(require('../../styles.module.css'));
|
|
14
14
|
const styles_module_scss_2 = __importDefault(require('./styles.module.css'));
|
|
15
15
|
const SubCategoryTitle_1 = require("./SubCategoryTitle");
|
|
16
|
+
const NOOP = () => { };
|
|
16
17
|
function SubCategory({ groupId, service, showDescription, isMobile, dragDisabled, favorite, onServiceClick, groupFavoritesEnabled, }) {
|
|
17
18
|
const subcategoryId = (0, innerLink_1.getSubCategoryId)(groupId, service.id);
|
|
18
19
|
const nestedGroupId = (0, innerLink_1.getNestedServiceGroupId)(groupId, service.id);
|
|
19
20
|
const nestedItems = (0, react_1.useMemo)(() => service.items?.filter(item => !item.hidden) ?? [], [service.items]);
|
|
20
|
-
const
|
|
21
|
+
const hasItems = nestedItems.length > 0;
|
|
22
|
+
const viewMode = service.viewMode ?? 'expanded';
|
|
23
|
+
const isExpandableEnabled = hasItems && viewMode === 'expandable';
|
|
21
24
|
// Раскрытие подкатегории — локальное uncontrolled состояние: наружу его пока не выводим.
|
|
22
|
-
const [isExpanded, setIsExpanded] = (0, react_1.useState)(subcategoryId);
|
|
25
|
+
const [isExpanded, setIsExpanded] = (0, react_1.useState)(hasItems ? subcategoryId : undefined);
|
|
23
26
|
const handleExpandedChange = (0, react_1.useCallback)(() => {
|
|
24
27
|
if (isExpandableEnabled) {
|
|
25
28
|
setIsExpanded(isExpanded ? undefined : subcategoryId);
|
|
26
29
|
}
|
|
27
30
|
}, [isExpanded, subcategoryId, isExpandableEnabled]);
|
|
31
|
+
// 'group-title-only' — только заголовок подкатегории, без раскрываемого тела и кнопки
|
|
32
|
+
// переключения: карточка ведёт себя как обычная ссылка (см. isSubCategoryCard в utils/innerLink).
|
|
33
|
+
if (viewMode === 'group-title-only') {
|
|
34
|
+
return ((0, jsx_runtime_1.jsx)("div", { className: styles_module_scss_2.default.subcategory, "data-title-only": true, "data-test-id": `${constants_1.TEST_IDS.subcategory}-${service.id}`, children: (0, jsx_runtime_1.jsx)(SubCategoryTitle_1.SubCategoryTitle, { groupId: groupId, service: service, expandable: { value: true, onClick: NOOP }, showDescription: showDescription, isMobile: isMobile, dragDisabled: dragDisabled, favorite: groupFavoritesEnabled ? favorite : undefined, onServiceClick: onServiceClick }) }));
|
|
35
|
+
}
|
|
36
|
+
if (viewMode === 'expanded') {
|
|
37
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: styles_module_scss_2.default.subcategory, "data-test-id": `${constants_1.TEST_IDS.subcategory}-${service.id}`, children: [(0, jsx_runtime_1.jsx)(SubCategoryTitle_1.SubCategoryTitle, { groupId: groupId, service: service, expandable: {
|
|
38
|
+
value: Boolean(isExpanded),
|
|
39
|
+
onClick: handleExpandedChange,
|
|
40
|
+
}, showDescription: showDescription, isMobile: isMobile, dragDisabled: dragDisabled, favorite: groupFavoritesEnabled ? favorite : undefined, onServiceClick: onServiceClick }), (0, jsx_runtime_1.jsx)("div", { className: styles_module_scss_1.default.groupBody, "data-subcategory-body": 'expanded', "data-mobile": isMobile || undefined, children: nestedItems.map(nestedService => ((0, jsx_runtime_1.jsx)(ServiceCard_1.DraggableServiceCard, { groupId: nestedGroupId, service: nestedService, favorite: favorite, isMobile: isMobile, onServiceClick: onServiceClick, showDescription: showDescription, dragDisabled: dragDisabled }, nestedGroupId + nestedService.id))) })] }));
|
|
41
|
+
}
|
|
28
42
|
return ((0, jsx_runtime_1.jsx)("div", { className: styles_module_scss_2.default.subcategory, "data-test-id": `${constants_1.TEST_IDS.subcategory}-${service.id}`, children: (0, jsx_runtime_1.jsx)(accordion_1.Accordion, { selectionMode: 'single', expanded: isExpanded, onExpandedChange: handleExpandedChange, children: (0, jsx_runtime_1.jsx)(accordion_1.Accordion.CollapseBlockTertiary, { id: subcategoryId, showChevron: false, className: styles_module_scss_2.default.subcategoryAccordion, afterTitle: (0, jsx_runtime_1.jsx)(SubCategoryTitle_1.SubCategoryTitle, { groupId: groupId, service: service, expandable: {
|
|
29
43
|
value: Boolean(isExpanded),
|
|
30
44
|
onClick: handleExpandedChange,
|
|
@@ -9,12 +9,18 @@
|
|
|
9
9
|
.subcategory{
|
|
10
10
|
min-width:0;
|
|
11
11
|
}
|
|
12
|
-
.subcategory:has([data-subcategory-body]){
|
|
12
|
+
.subcategory:has([data-subcategory-body]), .subcategory[data-title-only]{
|
|
13
13
|
grid-column:1/-1;
|
|
14
14
|
padding:0 var(--sn-primitive-dimension-4, 4px);
|
|
15
15
|
border-radius:var(--sn-density-radius-2xs, var(--sn-primitive-dimension-4, 4px));
|
|
16
16
|
background-color:var(--sn-theme-color-neutral-decorTransparent, var(--sn-brand-color-neutral-transparent-forLightMode, rgba(124, 131, 182, 0.0784313725)));
|
|
17
17
|
}
|
|
18
|
+
.subcategory[data-title-only]{
|
|
19
|
+
padding:var(--sn-primitive-dimension-4, 4px);
|
|
20
|
+
}
|
|
21
|
+
.subcategory:has([data-subcategory-body=expanded]){
|
|
22
|
+
padding:var(--sn-primitive-dimension-4, 4px) var(--sn-primitive-dimension-4, 4px) 0;
|
|
23
|
+
}
|
|
18
24
|
|
|
19
25
|
.subcategoryAccordion{
|
|
20
26
|
min-width:0;
|
|
@@ -120,6 +120,9 @@
|
|
|
120
120
|
.groupBody[data-subcategory-body]{
|
|
121
121
|
padding-bottom:var(--sn-primitive-dimension-4, 4px);
|
|
122
122
|
}
|
|
123
|
+
.groupBody[data-subcategory-body=expanded]{
|
|
124
|
+
padding-top:var(--sn-accordion-anatomy-accordionTertiary-container-bodyContent-paddingVertical, var(--sn-primitive-dimension-4, 4px));
|
|
125
|
+
}
|
|
123
126
|
|
|
124
127
|
.decoration{
|
|
125
128
|
--highlight-border-width:1px;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
align-items:center;
|
|
6
6
|
box-sizing:border-box;
|
|
7
7
|
width:100%;
|
|
8
|
-
min-height:
|
|
8
|
+
min-height:var(--sn-primitive-dimension-88, 88px);
|
|
9
9
|
padding:var(--sn-primitive-dimension-8, 8px) 0 0;
|
|
10
10
|
border-radius:var(--sn-density-radius-2xs, var(--sn-primitive-dimension-4, 4px));
|
|
11
11
|
background:var(--sn-theme-color-neutral-background1Level, var(--sn-brand-color-neutral-95, var(--sn-primitive-color-gray-95, #fdfdfd)));
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
position:relative;
|
|
33
33
|
flex:1 1 auto;
|
|
34
34
|
width:100%;
|
|
35
|
-
min-height:
|
|
35
|
+
min-height:var(--sn-primitive-dimension-44, 44px);
|
|
36
36
|
}
|
|
37
37
|
.listScroll[data-insert-new] [data-favorite]{
|
|
38
38
|
fill:var(--sn-theme-color-primary-accent, var(--sn-brand-color-primary-55, var(--sn-brandRole-color-brandA-55, var(--sn-primitive-color-brandA-55, #389f74))));
|
|
@@ -51,8 +51,5 @@ function DraggableServiceCard({ groupId, service, favorite, dragDisabled, ...pro
|
|
|
51
51
|
disabled,
|
|
52
52
|
});
|
|
53
53
|
const { tabIndex, ...restAttributes } = attributes ?? {};
|
|
54
|
-
if (disabled) {
|
|
55
|
-
return (0, jsx_runtime_1.jsx)(ServiceCard, { service: service, favorite: favorite, ...props, tabIndex: tabIndex });
|
|
56
|
-
}
|
|
57
54
|
return ((0, jsx_runtime_1.jsx)(drag_and_drop_1.DragGhost, { innerRef: setNodeRef, className: styles_module_scss_1.default.draggableCard, dragging: isDragging, mode: drag_and_drop_1.DRAG_MODE.Static, ...listeners, ...restAttributes, children: (0, jsx_runtime_1.jsx)(ServiceCard, { service: service, favorite: favorite, ...props, tabIndex: tabIndex }) }));
|
|
58
55
|
}
|
|
@@ -4,6 +4,7 @@ import { CardServiceLightProps } from '@cloud-ru/ds-uikit-product-card-predefine
|
|
|
4
4
|
import { JSXElementConstructor, MouseEvent, ReactNode } from 'react';
|
|
5
5
|
import { ContentProps } from './helperComponents/Content';
|
|
6
6
|
import { FavoritesSegment } from './helperComponents/Favorites/constants';
|
|
7
|
+
export type InnerLinkViewMode = 'group-title-only' | 'flat-link' | 'expanded' | 'expandable';
|
|
7
8
|
/**
|
|
8
9
|
* Карточка сервиса или ссылки внутри {@link LinksGroup}.
|
|
9
10
|
*
|
|
@@ -36,15 +37,25 @@ export type InnerLink = {
|
|
|
36
37
|
badge?: CardServiceLightProps['promoTag'];
|
|
37
38
|
/** Разрешено ли добавление карточки в избранное. default=true - разрешено */
|
|
38
39
|
favoritesEnabled?: boolean;
|
|
39
|
-
/**
|
|
40
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Режим отображения карточки. default='expandable'.
|
|
42
|
+
*
|
|
43
|
+
* - `'expandable'` — подкатегория при наличии реальных {@link items}: заголовок
|
|
44
|
+
* {@link TitleClickable} с шевроном и сетка вложенных сервисов (раскрытие/схлопывание —
|
|
45
|
+
* см. {@link expandableEnabled}). Без `items` — обычная карточка сервиса.
|
|
46
|
+
* - `'group-title-only'` — заголовок подкатегории ({@link TitleClickable} с шевроном) без
|
|
47
|
+
* раскрываемого тела, даже если `items` заданы: карточка ведёт себя как обычная ссылка.
|
|
48
|
+
* Полезно для группы, чьи вложенные сервисы показываются на отдельной странице.
|
|
49
|
+
* - `'flat-link'` — всегда обычная карточка сервиса, даже если `items` заданы.
|
|
50
|
+
*/
|
|
51
|
+
viewMode?: InnerLinkViewMode;
|
|
41
52
|
/**
|
|
42
53
|
* Вложенные сервисы подкатегории.
|
|
43
54
|
*
|
|
44
55
|
* При наличии карточка раскрывается аккордеоном: в свёрнутом виде — обычная карточка
|
|
45
56
|
* с кнопкой раскрытия, в развёрнутом — заголовок {@link TitleClickable} и сетка вложенных сервисов.
|
|
46
57
|
*/
|
|
47
|
-
items?: InnerLink[];
|
|
58
|
+
items?: Omit<InnerLink, 'items' | 'viewMode' | 'expandableEnabled'>[];
|
|
48
59
|
/**
|
|
49
60
|
* Синонимы для fuzzy-поиска.
|
|
50
61
|
*/
|
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
import { InnerLink, LinksGroup } from '../types';
|
|
2
2
|
export declare function hasNestedItems(item: InnerLink): boolean;
|
|
3
|
+
/**
|
|
4
|
+
* Рендерится ли карточка как подкатегория (заголовок {@link TitleClickable} + вложенная сетка).
|
|
5
|
+
*
|
|
6
|
+
* Решение зависит от `viewMode` (не указан — считается `'expandable'`):
|
|
7
|
+
* - `'flat-link'` — никогда, карточка всегда обычная ссылка, даже если `items` заданы.
|
|
8
|
+
* - `'group-title-only'` — всегда, даже без `items`: только заголовок, без раскрываемого тела
|
|
9
|
+
* и кнопки переключения — карточка ведёт себя как обычная ссылка.
|
|
10
|
+
* - `'expandable'` — только при наличии реальных вложенных сервисов.
|
|
11
|
+
*/
|
|
12
|
+
export declare function isSubCategoryCard(item: InnerLink): boolean;
|
|
3
13
|
export declare function flatInnerLinks(items?: InnerLink[]): InnerLink[];
|
|
4
14
|
export declare function getLinksGroupVisibleItemsCount(group: LinksGroup): number;
|
|
5
15
|
export declare function getSubCategoryId(groupId: string, serviceId: string): string;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.hasNestedItems = hasNestedItems;
|
|
4
|
+
exports.isSubCategoryCard = isSubCategoryCard;
|
|
4
5
|
exports.flatInnerLinks = flatInnerLinks;
|
|
5
6
|
exports.getLinksGroupVisibleItemsCount = getLinksGroupVisibleItemsCount;
|
|
6
7
|
exports.getSubCategoryId = getSubCategoryId;
|
|
@@ -9,6 +10,25 @@ exports.findNestedInnerLinkParent = findNestedInnerLinkParent;
|
|
|
9
10
|
function hasNestedItems(item) {
|
|
10
11
|
return Boolean(item.items?.some(child => !child.hidden));
|
|
11
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* Рендерится ли карточка как подкатегория (заголовок {@link TitleClickable} + вложенная сетка).
|
|
15
|
+
*
|
|
16
|
+
* Решение зависит от `viewMode` (не указан — считается `'expandable'`):
|
|
17
|
+
* - `'flat-link'` — никогда, карточка всегда обычная ссылка, даже если `items` заданы.
|
|
18
|
+
* - `'group-title-only'` — всегда, даже без `items`: только заголовок, без раскрываемого тела
|
|
19
|
+
* и кнопки переключения — карточка ведёт себя как обычная ссылка.
|
|
20
|
+
* - `'expandable'` — только при наличии реальных вложенных сервисов.
|
|
21
|
+
*/
|
|
22
|
+
function isSubCategoryCard(item) {
|
|
23
|
+
const viewMode = item.viewMode ?? 'expanded';
|
|
24
|
+
if (viewMode === 'flat-link') {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
if (viewMode === 'group-title-only') {
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
return hasNestedItems(item);
|
|
31
|
+
}
|
|
12
32
|
function flatInnerLinks(items = []) {
|
|
13
33
|
return items.flatMap(item => {
|
|
14
34
|
if (item.hidden) {
|
package/dist/cjs/style.css
CHANGED
|
@@ -103,28 +103,24 @@
|
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
.root{
|
|
106
|
+
width:100%;
|
|
107
|
+
min-width:0;
|
|
108
|
+
}
|
|
109
|
+
.root:hover .closeButton, .root:focus-visible .closeButton, .root:has(*:focus-visible) .closeButton{
|
|
110
|
+
visibility:visible;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.contentRow{
|
|
106
114
|
position:relative;
|
|
107
115
|
display:flex;
|
|
108
|
-
gap:var(--sn-primitive-dimension-
|
|
116
|
+
gap:var(--sn-density-spacing-interval-s, var(--sn-primitive-dimension-8, 8px));
|
|
109
117
|
align-items:center;
|
|
110
118
|
box-sizing:border-box;
|
|
111
119
|
width:100%;
|
|
112
120
|
min-width:0;
|
|
113
|
-
min-height:var(--sn-primitive-dimension-
|
|
121
|
+
min-height:var(--sn-primitive-dimension-40, 40px);
|
|
114
122
|
padding:0 var(--sn-primitive-dimension-12, 12px);
|
|
115
|
-
border-radius:
|
|
116
|
-
font:inherit;
|
|
117
|
-
color:inherit;
|
|
118
|
-
text-align:left;
|
|
119
|
-
text-decoration:none;
|
|
120
|
-
background-color:var(--sn-theme-color-neutral-background1Level, var(--sn-brand-color-neutral-95, var(--sn-primitive-color-gray-95, #fdfdfd)));
|
|
121
|
-
}
|
|
122
|
-
.root:hover .closeButton, .root:focus-visible .closeButton, .root:focus-within .closeButton{
|
|
123
|
-
visibility:visible;
|
|
124
|
-
}
|
|
125
|
-
.root:focus-visible{
|
|
126
|
-
outline:var(--sn-theme-color-available-complementary, #000000) solid var(--sn-primitive-strokeWeight-strokeSemiBold, 2px);
|
|
127
|
-
outline-offset:var(--sn-primitive-strokeWeight-strokeSemiBold, 2px);
|
|
123
|
+
border-radius:inherit;
|
|
128
124
|
}
|
|
129
125
|
|
|
130
126
|
.titleWrapper{
|
|
@@ -207,12 +203,18 @@
|
|
|
207
203
|
.subcategory{
|
|
208
204
|
min-width:0;
|
|
209
205
|
}
|
|
210
|
-
.subcategory:has([data-subcategory-body]){
|
|
206
|
+
.subcategory:has([data-subcategory-body]), .subcategory[data-title-only]{
|
|
211
207
|
grid-column:1/-1;
|
|
212
208
|
padding:0 var(--sn-primitive-dimension-4, 4px);
|
|
213
209
|
border-radius:var(--sn-density-radius-2xs, var(--sn-primitive-dimension-4, 4px));
|
|
214
210
|
background-color:var(--sn-theme-color-neutral-decorTransparent, var(--sn-brand-color-neutral-transparent-forLightMode, rgba(124, 131, 182, 0.0784313725)));
|
|
215
211
|
}
|
|
212
|
+
.subcategory[data-title-only]{
|
|
213
|
+
padding:var(--sn-primitive-dimension-4, 4px);
|
|
214
|
+
}
|
|
215
|
+
.subcategory:has([data-subcategory-body=expanded]){
|
|
216
|
+
padding:var(--sn-primitive-dimension-4, 4px) var(--sn-primitive-dimension-4, 4px) 0;
|
|
217
|
+
}
|
|
216
218
|
|
|
217
219
|
.subcategoryAccordion{
|
|
218
220
|
min-width:0;
|
|
@@ -387,6 +389,9 @@
|
|
|
387
389
|
.groupBody[data-subcategory-body]{
|
|
388
390
|
padding-bottom:var(--sn-primitive-dimension-4, 4px);
|
|
389
391
|
}
|
|
392
|
+
.groupBody[data-subcategory-body=expanded]{
|
|
393
|
+
padding-top:var(--sn-accordion-anatomy-accordionTertiary-container-bodyContent-paddingVertical, var(--sn-primitive-dimension-4, 4px));
|
|
394
|
+
}
|
|
390
395
|
|
|
391
396
|
.decoration{
|
|
392
397
|
--highlight-border-width:1px;
|
|
@@ -540,7 +545,7 @@
|
|
|
540
545
|
align-items:center;
|
|
541
546
|
box-sizing:border-box;
|
|
542
547
|
width:100%;
|
|
543
|
-
min-height:
|
|
548
|
+
min-height:var(--sn-primitive-dimension-88, 88px);
|
|
544
549
|
padding:var(--sn-primitive-dimension-8, 8px) 0 0;
|
|
545
550
|
border-radius:var(--sn-density-radius-2xs, var(--sn-primitive-dimension-4, 4px));
|
|
546
551
|
background:var(--sn-theme-color-neutral-background1Level, var(--sn-brand-color-neutral-95, var(--sn-primitive-color-gray-95, #fdfdfd)));
|
|
@@ -567,7 +572,7 @@
|
|
|
567
572
|
position:relative;
|
|
568
573
|
flex:1 1 auto;
|
|
569
574
|
width:100%;
|
|
570
|
-
min-height:
|
|
575
|
+
min-height:var(--sn-primitive-dimension-44, 44px);
|
|
571
576
|
}
|
|
572
577
|
.listScroll[data-insert-new] [data-favorite]{
|
|
573
578
|
fill:var(--sn-theme-color-primary-accent, var(--sn-brand-color-primary-55, var(--sn-brandRole-color-brandA-55, var(--sn-primitive-color-brandA-55, #389f74))));
|
|
@@ -13,4 +13,4 @@ export type MenuBannerProps = WithSupportProps<{
|
|
|
13
13
|
/** CSS-класс корневого элемента */
|
|
14
14
|
className?: string;
|
|
15
15
|
} & Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'title' | 'children'>>;
|
|
16
|
-
export declare function MenuBanner({ title, promoTag, afterTitle, onClose, className, href,
|
|
16
|
+
export declare function MenuBanner({ title, promoTag, afterTitle, onClose, className, href, 'data-test-id': dataTestId, ...rest }: MenuBannerProps): ReactElement;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Button } from '@cloud-ru/ds-button';
|
|
3
|
+
import { Card } from '@cloud-ru/ds-card';
|
|
3
4
|
import { CrossSVG } from '@cloud-ru/ds-icons/interface/system';
|
|
4
5
|
import { PromoTag, ROLE_APPEARANCE, SIZE } from '@cloud-ru/ds-promo-tag';
|
|
5
6
|
import { useThemeClassnames } from '@cloud-ru/ds-theme';
|
|
@@ -9,7 +10,7 @@ import { useCallback } from 'react';
|
|
|
9
10
|
import { headerLocale } from '../../../../locale/index.js';
|
|
10
11
|
import { MENU_BANNER_TEST_IDS } from './constants.js';
|
|
11
12
|
import styles from './styles.module.css';
|
|
12
|
-
export function MenuBanner({ title, promoTag, afterTitle, onClose, className, href = '#',
|
|
13
|
+
export function MenuBanner({ title, promoTag, afterTitle, onClose, className, href = '#', 'data-test-id': dataTestId, ...rest }) {
|
|
13
14
|
const { t } = headerLocale.useTranslations();
|
|
14
15
|
const compactThemeClassname = useThemeClassnames({ density: 'compact' });
|
|
15
16
|
const handleClose = useCallback(e => {
|
|
@@ -17,5 +18,5 @@ export function MenuBanner({ title, promoTag, afterTitle, onClose, className, hr
|
|
|
17
18
|
e.stopPropagation();
|
|
18
19
|
onClose?.(e);
|
|
19
20
|
}, [onClose]);
|
|
20
|
-
return (
|
|
21
|
+
return (_jsx(Card, { as: 'a', href: href, radius: 'l', view: 'simple', className: cn(styles.root, className), "data-test-id": dataTestId ?? MENU_BANNER_TEST_IDS.root, ...rest, children: _jsxs("div", { className: styles.contentRow, children: [_jsxs("span", { className: styles.titleWrapper, children: [_jsx(Typography, { as: 'span', variant: 'body', size: 'm', className: styles.title, "data-test-id": MENU_BANNER_TEST_IDS.title, children: title }), promoTag && (_jsx(PromoTag, { ...promoTag, roleAppearance: ROLE_APPEARANCE.Decor, size: SIZE.Xs, "data-test-id": MENU_BANNER_TEST_IDS.promoTag }))] }), afterTitle && (_jsx("div", { className: styles.afterTitle, "data-test-id": MENU_BANNER_TEST_IDS.afterTitle, children: afterTitle })), onClose && (_jsx(Button, { className: cn(styles.closeButton, compactThemeClassname), view: 'elevated', appearance: 'neutral', size: 's', icon: _jsx(CrossSVG, { size: 16 }), onClick: handleClose, "aria-label": t('close'), "data-test-id": MENU_BANNER_TEST_IDS.close }))] }) }));
|
|
21
22
|
}
|
|
@@ -10,28 +10,24 @@
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
.root{
|
|
13
|
+
width:100%;
|
|
14
|
+
min-width:0;
|
|
15
|
+
}
|
|
16
|
+
.root:hover .closeButton, .root:focus-visible .closeButton, .root:has(*:focus-visible) .closeButton{
|
|
17
|
+
visibility:visible;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.contentRow{
|
|
13
21
|
position:relative;
|
|
14
22
|
display:flex;
|
|
15
|
-
gap:var(--sn-primitive-dimension-
|
|
23
|
+
gap:var(--sn-density-spacing-interval-s, var(--sn-primitive-dimension-8, 8px));
|
|
16
24
|
align-items:center;
|
|
17
25
|
box-sizing:border-box;
|
|
18
26
|
width:100%;
|
|
19
27
|
min-width:0;
|
|
20
|
-
min-height:var(--sn-primitive-dimension-
|
|
28
|
+
min-height:var(--sn-primitive-dimension-40, 40px);
|
|
21
29
|
padding:0 var(--sn-primitive-dimension-12, 12px);
|
|
22
|
-
border-radius:
|
|
23
|
-
font:inherit;
|
|
24
|
-
color:inherit;
|
|
25
|
-
text-align:left;
|
|
26
|
-
text-decoration:none;
|
|
27
|
-
background-color:var(--sn-theme-color-neutral-background1Level, var(--sn-brand-color-neutral-95, var(--sn-primitive-color-gray-95, #fdfdfd)));
|
|
28
|
-
}
|
|
29
|
-
.root:hover .closeButton, .root:focus-visible .closeButton, .root:focus-within .closeButton{
|
|
30
|
-
visibility:visible;
|
|
31
|
-
}
|
|
32
|
-
.root:focus-visible{
|
|
33
|
-
outline:var(--sn-theme-color-available-complementary, #000000) solid var(--sn-primitive-strokeWeight-strokeSemiBold, 2px);
|
|
34
|
-
outline-offset:var(--sn-primitive-strokeWeight-strokeSemiBold, 2px);
|
|
30
|
+
border-radius:inherit;
|
|
35
31
|
}
|
|
36
32
|
|
|
37
33
|
.titleWrapper{
|
|
@@ -5,7 +5,7 @@ import { CrossSVG, SearchSVG } from '@cloud-ru/ds-icons/interface/system';
|
|
|
5
5
|
import { InfoBlock } from '@cloud-ru/ds-info-block';
|
|
6
6
|
import { useValueControl } from '@cloud-ru/ds-utils';
|
|
7
7
|
import cn from 'classnames';
|
|
8
|
-
import { useCallback, useDeferredValue,
|
|
8
|
+
import { useCallback, useDeferredValue, useMemo } from 'react';
|
|
9
9
|
import { headerLocale } from '../../../../locale/index.js';
|
|
10
10
|
import { shouldBeOpenedInNewTab } from '../../../../utils/shouldBeOpenedInNewTab.js';
|
|
11
11
|
import { getLinksGroupVisibleItemsCount, resolveGroupBlockColor } from '../../utils/index.js';
|
|
@@ -27,11 +27,6 @@ export function Content({ searchValue, search, rightTop, segments, searchGroups
|
|
|
27
27
|
});
|
|
28
28
|
const isSearching = Boolean(searchValue);
|
|
29
29
|
const enableServiceDrag = Boolean(favorite) && !isMobile && !isSearching;
|
|
30
|
-
useEffect(() => {
|
|
31
|
-
if (!segments?.some(segment => segment.id === segmentId) && defaultSegmentId) {
|
|
32
|
-
setSegmentId(defaultSegmentId);
|
|
33
|
-
}
|
|
34
|
-
}, [defaultSegmentId, segmentId, setSegmentId, segments]);
|
|
35
30
|
const handleLinkClick = useCallback((service, e) => {
|
|
36
31
|
if (service.disabled) {
|
|
37
32
|
e?.preventDefault();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { isSubCategoryCard } from '../../../../../utils/innerLink.js';
|
|
3
3
|
import { DraggableServiceCard } from '../../../../ServiceCard/index.js';
|
|
4
4
|
import styles from '../styles.module.css';
|
|
5
5
|
import { SubCategory } from './SubCategory/index.js';
|
|
@@ -9,7 +9,7 @@ export function SortableGroupCards({ groupId, items, showDescription, isMobile,
|
|
|
9
9
|
return null;
|
|
10
10
|
}
|
|
11
11
|
const key = String(groupId) + service.id;
|
|
12
|
-
if (
|
|
12
|
+
if (isSubCategoryCard(service)) {
|
|
13
13
|
return (_jsx(SubCategory, { groupId: groupId, service: service, showDescription: showDescription, isMobile: isMobile, dragDisabled: !enableServiceDrag, favorite: favorite, groupFavoritesEnabled: groupFavoritesEnabled, onServiceClick: onServiceClick }, key));
|
|
14
14
|
}
|
|
15
15
|
return (_jsx(DraggableServiceCard, { groupId: groupId, service: service, favorite: favorite, isMobile: isMobile, onServiceClick: onServiceClick, showDescription: showDescription, dragDisabled: !enableServiceDrag }, key));
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Accordion } from '@cloud-ru/ds-accordion';
|
|
3
3
|
import { useCallback, useMemo, useState } from 'react';
|
|
4
4
|
import { getNestedServiceGroupId, getSubCategoryId } from '../../../../../../utils/innerLink.js';
|
|
@@ -7,18 +7,32 @@ import { TEST_IDS } from '../../../../constants.js';
|
|
|
7
7
|
import baseGroupStyles from '../../styles.module.css';
|
|
8
8
|
import styles from './styles.module.css';
|
|
9
9
|
import { SubCategoryTitle } from './SubCategoryTitle.js';
|
|
10
|
+
const NOOP = () => { };
|
|
10
11
|
export function SubCategory({ groupId, service, showDescription, isMobile, dragDisabled, favorite, onServiceClick, groupFavoritesEnabled, }) {
|
|
11
12
|
const subcategoryId = getSubCategoryId(groupId, service.id);
|
|
12
13
|
const nestedGroupId = getNestedServiceGroupId(groupId, service.id);
|
|
13
14
|
const nestedItems = useMemo(() => service.items?.filter(item => !item.hidden) ?? [], [service.items]);
|
|
14
|
-
const
|
|
15
|
+
const hasItems = nestedItems.length > 0;
|
|
16
|
+
const viewMode = service.viewMode ?? 'expanded';
|
|
17
|
+
const isExpandableEnabled = hasItems && viewMode === 'expandable';
|
|
15
18
|
// Раскрытие подкатегории — локальное uncontrolled состояние: наружу его пока не выводим.
|
|
16
|
-
const [isExpanded, setIsExpanded] = useState(subcategoryId);
|
|
19
|
+
const [isExpanded, setIsExpanded] = useState(hasItems ? subcategoryId : undefined);
|
|
17
20
|
const handleExpandedChange = useCallback(() => {
|
|
18
21
|
if (isExpandableEnabled) {
|
|
19
22
|
setIsExpanded(isExpanded ? undefined : subcategoryId);
|
|
20
23
|
}
|
|
21
24
|
}, [isExpanded, subcategoryId, isExpandableEnabled]);
|
|
25
|
+
// 'group-title-only' — только заголовок подкатегории, без раскрываемого тела и кнопки
|
|
26
|
+
// переключения: карточка ведёт себя как обычная ссылка (см. isSubCategoryCard в utils/innerLink).
|
|
27
|
+
if (viewMode === 'group-title-only') {
|
|
28
|
+
return (_jsx("div", { className: styles.subcategory, "data-title-only": true, "data-test-id": `${TEST_IDS.subcategory}-${service.id}`, children: _jsx(SubCategoryTitle, { groupId: groupId, service: service, expandable: { value: true, onClick: NOOP }, showDescription: showDescription, isMobile: isMobile, dragDisabled: dragDisabled, favorite: groupFavoritesEnabled ? favorite : undefined, onServiceClick: onServiceClick }) }));
|
|
29
|
+
}
|
|
30
|
+
if (viewMode === 'expanded') {
|
|
31
|
+
return (_jsxs("div", { className: styles.subcategory, "data-test-id": `${TEST_IDS.subcategory}-${service.id}`, children: [_jsx(SubCategoryTitle, { groupId: groupId, service: service, expandable: {
|
|
32
|
+
value: Boolean(isExpanded),
|
|
33
|
+
onClick: handleExpandedChange,
|
|
34
|
+
}, showDescription: showDescription, isMobile: isMobile, dragDisabled: dragDisabled, favorite: groupFavoritesEnabled ? favorite : undefined, onServiceClick: onServiceClick }), _jsx("div", { className: baseGroupStyles.groupBody, "data-subcategory-body": 'expanded', "data-mobile": isMobile || undefined, children: nestedItems.map(nestedService => (_jsx(DraggableServiceCard, { groupId: nestedGroupId, service: nestedService, favorite: favorite, isMobile: isMobile, onServiceClick: onServiceClick, showDescription: showDescription, dragDisabled: dragDisabled }, nestedGroupId + nestedService.id))) })] }));
|
|
35
|
+
}
|
|
22
36
|
return (_jsx("div", { className: styles.subcategory, "data-test-id": `${TEST_IDS.subcategory}-${service.id}`, children: _jsx(Accordion, { selectionMode: 'single', expanded: isExpanded, onExpandedChange: handleExpandedChange, children: _jsx(Accordion.CollapseBlockTertiary, { id: subcategoryId, showChevron: false, className: styles.subcategoryAccordion, afterTitle: _jsx(SubCategoryTitle, { groupId: groupId, service: service, expandable: {
|
|
23
37
|
value: Boolean(isExpanded),
|
|
24
38
|
onClick: handleExpandedChange,
|
|
@@ -9,12 +9,18 @@
|
|
|
9
9
|
.subcategory{
|
|
10
10
|
min-width:0;
|
|
11
11
|
}
|
|
12
|
-
.subcategory:has([data-subcategory-body]){
|
|
12
|
+
.subcategory:has([data-subcategory-body]), .subcategory[data-title-only]{
|
|
13
13
|
grid-column:1/-1;
|
|
14
14
|
padding:0 var(--sn-primitive-dimension-4, 4px);
|
|
15
15
|
border-radius:var(--sn-density-radius-2xs, var(--sn-primitive-dimension-4, 4px));
|
|
16
16
|
background-color:var(--sn-theme-color-neutral-decorTransparent, var(--sn-brand-color-neutral-transparent-forLightMode, rgba(124, 131, 182, 0.0784313725)));
|
|
17
17
|
}
|
|
18
|
+
.subcategory[data-title-only]{
|
|
19
|
+
padding:var(--sn-primitive-dimension-4, 4px);
|
|
20
|
+
}
|
|
21
|
+
.subcategory:has([data-subcategory-body=expanded]){
|
|
22
|
+
padding:var(--sn-primitive-dimension-4, 4px) var(--sn-primitive-dimension-4, 4px) 0;
|
|
23
|
+
}
|
|
18
24
|
|
|
19
25
|
.subcategoryAccordion{
|
|
20
26
|
min-width:0;
|
|
@@ -120,6 +120,9 @@
|
|
|
120
120
|
.groupBody[data-subcategory-body]{
|
|
121
121
|
padding-bottom:var(--sn-primitive-dimension-4, 4px);
|
|
122
122
|
}
|
|
123
|
+
.groupBody[data-subcategory-body=expanded]{
|
|
124
|
+
padding-top:var(--sn-accordion-anatomy-accordionTertiary-container-bodyContent-paddingVertical, var(--sn-primitive-dimension-4, 4px));
|
|
125
|
+
}
|
|
123
126
|
|
|
124
127
|
.decoration{
|
|
125
128
|
--highlight-border-width:1px;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
align-items:center;
|
|
6
6
|
box-sizing:border-box;
|
|
7
7
|
width:100%;
|
|
8
|
-
min-height:
|
|
8
|
+
min-height:var(--sn-primitive-dimension-88, 88px);
|
|
9
9
|
padding:var(--sn-primitive-dimension-8, 8px) 0 0;
|
|
10
10
|
border-radius:var(--sn-density-radius-2xs, var(--sn-primitive-dimension-4, 4px));
|
|
11
11
|
background:var(--sn-theme-color-neutral-background1Level, var(--sn-brand-color-neutral-95, var(--sn-primitive-color-gray-95, #fdfdfd)));
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
position:relative;
|
|
33
33
|
flex:1 1 auto;
|
|
34
34
|
width:100%;
|
|
35
|
-
min-height:
|
|
35
|
+
min-height:var(--sn-primitive-dimension-44, 44px);
|
|
36
36
|
}
|
|
37
37
|
.listScroll[data-insert-new] [data-favorite]{
|
|
38
38
|
fill:var(--sn-theme-color-primary-accent, var(--sn-brand-color-primary-55, var(--sn-brandRole-color-brandA-55, var(--sn-primitive-color-brandA-55, #389f74))));
|