@cloud-ru/ds-uikit-product-header 1.2.1-preview-02275c87.0 → 1.2.2-preview-bf64a5bb.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/CHANGELOG.md CHANGED
@@ -3,6 +3,10 @@
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.2.1 (2026-09-01)
7
+
8
+ **Note:** Version bump only for package @ds/uikit-product-header
9
+
6
10
  # 1.2.0 (2026-09-01)
7
11
 
8
12
  ### Bug Fixes
package/README.md CHANGED
@@ -2,19 +2,6 @@
2
2
 
3
3
  `@cloud-ru/ds-uikit-product-header` — Продуктовая шапка консоли — HeaderLayout, MainMenu, UserMenu, Logo, PathBreadcrumbs и PlatformLogo.
4
4
 
5
- `@cloud-ru/ds-uikit-product-header` — новая продуктовая шапка консоли на Snack V2: layout, главное меню с сегментами и избранным, меню пользователя, логотип и хлебные крошки.
6
-
7
- ## Когда использовать
8
-
9
- - Новая навигация консоли с сегментами сервисов, избранным и настройками отображения карточек.
10
- - Полная замена header на Snack V2 без legacy-контрактов Figma `headerOld` / `navigationOldDrawer`.
11
- - Поэтапная миграция: `MenuMobile` (bottom sheet) подключается к legacy **`MainMenu`** через `customMobileMenu`.
12
-
13
- Когда **не** нужен:
14
-
15
- - Обратная совместимость со старым drawer и API `serviceGroups` / `LinksGroup`:
16
- - используйте **`@cloud-ru/ds-uikit-product-header-legacy`**.
17
-
18
5
  ## Установка
19
6
 
20
7
  ```bash
@@ -22,15 +9,10 @@ pnpm add @cloud-ru/ds-uikit-product-header
22
9
  ```
23
10
 
24
11
  ```ts
25
- import { HeaderLayout, MainMenu, MenuMobile, UserMenu } from '@cloud-ru/ds-uikit-product-header';
12
+ import { HeaderLayout, MainMenu, UserMenu } from '@cloud-ru/ds-uikit-product-header';
26
13
  import '@cloud-ru/ds-uikit-product-header/style.css';
27
14
  ```
28
15
 
29
- ## Смотри также
30
-
31
- - **`@cloud-ru/ds-uikit-product-header-legacy`** — legacy-шапка для параллельного релиза и `customMobileMenu`.
32
- - **`@cloud-ru/ds-adaptive`** — `AdaptiveProvider` / `layoutType` для desktop/mobile поверхностей.
33
-
34
16
  ## HeaderLayout
35
17
 
36
18
  Компоновка слотов продуктовой шапки — меню, логотип, селектор, хлебные крошки и тулбар.
@@ -110,56 +92,12 @@ export function PartialSlots() {
110
92
 
111
93
  Главное меню навигации — сегменты сервисов, поиск, избранное и настройки отображения.
112
94
 
113
- `MainMenu` — drawer с каталогом сервисов: сегменты, fuzzy-поиск, избранное, DnD групп и карточек.
114
-
115
- - **Desktop** — resizable `@cloud-ru/ds-drawer` слева: левая колонка (избранное, настройки), правая — сегменты и сетка карточек.
116
- - **Mobile** — fullscreen bottom sheet (`MobileDrawerCustom`, `position='bottom'`): sticky header с логотипом, scroll-body, поиск и каталог.
117
-
118
- Поверхность выбирается через `AdaptiveProvider` (`layoutType`).
95
+ `MainMenu` — drawer с каталогом сервисов: сегменты, fuzzy-поиск, избранное, DnD групп и карточек. На desktop — resizable drawer, на mobile — fullscreen.
119
96
 
120
97
  ### Когда использовать
121
98
 
122
- - Навигация по каталогу облачных сервисов из шапки консоли (новая продуктовая навигация).
99
+ - Навигация по каталогу облачных сервисов из шапки консоли.
123
100
  - Сценарии с избранным, недавними сервисами и настройками отображения карточек.
124
- - Mobile-меню для микрофронта на legacy **`HeaderLayout`**: `MenuMobile` подключается через `customMobileMenu` у **`@cloud-ru/ds-uikit-product-header-legacy` / MainMenu**.
125
-
126
- Когда **не** нужен:
127
-
128
- - Legacy drawer по Figma `navigationOldDrawer` / `navigationOldDrawerMobile`:
129
- - используйте **`@cloud-ru/ds-uikit-product-header-legacy`**.
130
-
131
- ### Анатомия
132
-
133
- #### Trigger и drawer
134
-
135
- - trigger — `HeaderButton` с `MainMenuSVG` и tooltip «Сервисы».
136
- - desktop drawer — resizable `DrawerCustom`, слева; drag-handle для ширины.
137
- - mobile drawer — fullscreen bottom sheet; swipe отключён (`swipeEnabled={false}`).
138
-
139
- #### Левая колонка (desktop)
140
-
141
- - `leftTop` — слот над избранным (например, селектор платформы).
142
- - `Favorites` — избранные сервисы с DnD (`MainMenuDndContext`).
143
- - `settingItems` — административные пункты (`mapInnerLinksToListItems`).
144
- - `leftBottom` — дополнительный слот внизу колонки.
145
-
146
- #### Правая колонка (desktop)
147
-
148
- - `rightTop` — баннеры.
149
- - `Search` — fuzzy-поиск по каталогу.
150
- - `segments` — сегменты с `SegmentControl` (если сегментов > 1).
151
- - Сетка карточек `CardServiceSmall` по группам в активном сегменте.
152
-
153
- #### Mobile body
154
-
155
- - `MenuHeaderBrand` + divider — sticky header с кнопкой закрытия.
156
- - `leftTop`, `Search`, `rightTop`, `Content` — в scroll-body.
157
- - `settingItems` / `leftBottom` — нижняя зона (`MenuBottom`).
158
- - Избранное без drag&drop (desktop-only DnD).
159
-
160
- #### open / setOpen
161
-
162
- Controlled-открытие drawer. Без `open` состояние держит сам компонент.
163
101
 
164
102
  ### Примеры использования
165
103
 
@@ -257,33 +195,6 @@ export function WithFavorites() {
257
195
  }
258
196
  ```
259
197
 
260
- #### Интеграция с legacy MainMenu
261
-
262
- ```tsx
263
- import { useState } from 'react';
264
- import { MainMenu as LegacyMainMenu } from '@cloud-ru/ds-uikit-product-header-legacy';
265
- import { MenuMobile } from '@cloud-ru/ds-uikit-product-header';
266
-
267
- function LocalMainMenu() {
268
- const [open, setOpen] = useState(false);
269
-
270
- return (
271
- <LegacyMainMenu
272
- open={open}
273
- setOpen={setOpen}
274
- serviceGroups={legacyGroups}
275
- customMobileMenu={
276
- <MenuMobile
277
- open={open}
278
- setOpen={setOpen}
279
- segments={headerSegments}
280
- />
281
- }
282
- />
283
- );
284
- }
285
- ```
286
-
287
198
  ### Props
288
199
 
289
200
  **MainMenuProps**
@@ -342,6 +253,7 @@ function LocalMainMenu() {
342
253
  | `badge` | `CardServiceLightProps` \| `PromoTagPredefinedBaseProps` | — | |
343
254
  | `description` | `string \| undefined` | — | Краткое описание сервиса — отображается при включённом переключателе «Описание». |
344
255
  | `disabled` | `boolean \| undefined` | — | |
256
+ | `favoritesEnabled` | `boolean \| undefined` | — | Разрешено ли добавление карточки в избранное. default=true - разрешено |
345
257
  | `hidden` | `boolean \| undefined` | — | |
346
258
  | `href` | `string \| undefined` | — | |
347
259
  | `icon` | `JSXElementConstructor<{ size?: number; className?: string; }> \| undefined` | — | Иконка карточки. |
@@ -441,185 +353,6 @@ function LocalMainMenu() {
441
353
  | `onClick` | `undefined` | — | |
442
354
  | `text` | `string` | — | |
443
355
 
444
- ### Смотри также
445
-
446
- - **`@cloud-ru/ds-uikit-product-header-legacy` / MainMenu** — legacy drawer и проп `customMobileMenu`.
447
- - **`@cloud-ru/ds-uikit-product-card-predefined`** — карточки сервисов в сетке.
448
- ### MenuMobile
449
-
450
- `MenuMobile` экспортируется из `@cloud-ru/ds-uikit-product-header` отдельно от `MainMenu` — тот же API (`MainMenuProps`), но без кнопки-триггера. Используется:
451
-
452
- - внутри `MainMenu` на mobile-поверхности;
453
- - в legacy-интеграции: `customMobileMenu` у `@cloud-ru/ds-uikit-product-header-legacy` / `MainMenu`.
454
-
455
- ```ts
456
- import { MainMenu, MenuMobile } from '@cloud-ru/ds-uikit-product-header';
457
- ```
458
-
459
- **MainMenuProps**
460
-
461
- | Prop | Type | Default | Description |
462
- |------|------|---------|-------------|
463
- | `activeSegmentId` | `string` | — | Активный сегмент правой панели (значение SegmentControl, см. {@link MainMenuSegment.id}). <br/> Не передано — неуправляемое состояние (дефолт — первый сегмент с видимыми карточками). |
464
- | `defaultWidth` | `number` | — | Ширина дровера, с которой открывается меню (desktop only) |
465
- | `disabled` | `boolean` | — | |
466
- | `draggerTooltip` | `string` | — | Текст подсказки для драггера (desktop only) |
467
- | `favorite` | `FavoriteProps` | — | |
468
- | `leftBottom` | `ReactNode` | — | |
469
- | `leftTop` | `ReactNode` | — | |
470
- | `loading` | `boolean` | — | Флаг загрузки данных |
471
- | `logo` | `ReactNode` | — | |
472
- | `onActiveSegmentChange` | `((segmentId: string) => void)` | — | Колбэк смены активного сегмента правой панели. |
473
- | `onSegmentExpandedChange` | `((segmentId: string, expandedGroupIds: string[]) => void)` | — | Колбэк при изменении набора раскрытых групп сегмента <br/> (без id синтетической группы избранного). |
474
- | `onSegmentOrderChange` | `((segmentId: string, orderedGroupIds: string[]) => void)` | — | Колбэк после DnD групп в сегменте (без id синтетической группы избранного). |
475
- | `onSegmentServiceClick` | `((service: InnerLink, e?: MouseEvent<HTMLElement, MouseEvent>) => void)` | — | Колбэк клика по карточке сервиса в сегменте. |
476
- | `onWidthChangeEnd` | `((width: number) => void)` | — | Вызывается при окончании изменения ширины дровера (desktop only) |
477
- | `open` | `boolean` | — | |
478
- | `platformGroups` | `LinksGroup` | — | Платформенные группы (например «Облачные продукты», «Другие продукты»). <br/> Без поиска в сетке карточек **не отображаются**. <br/> С поиском: попадают в результаты при совпадении; порядок — <br/> после совпадений из сегментов без `pinBottomOnSearch`, перед сегментами с `pinBottomOnSearch`. <br/> Обычно `favoritesEnabled: false`; карточки могут быть без `icon` (Avatar по `label`). |
479
- | `preferences` | `MainMenuPreferencesProps` | — | Настройки меню (модалка по кнопке в тулбаре): описания карточек, цвета групп. <br/> Не передано — кнопка настроек в тулбаре не отображается. |
480
- | `rightTop` | `ReactNode` | — | Слот над тулбаром правой колонки (например, баннеры) |
481
- | `search` | `SearchProps` | — | |
482
- | `searchGroups` | `LinksGroup` | — | Результаты поиска (уже смерженные); в обычном режиме не используются. |
483
- | `segmentPrefs` | `MainMenuSegmentPrefs` | — | Пользовательские prefs сегментов (порядок / раскрытие групп). <br/> Нет записи для сегмента или omit `order` / `expanded` → uncontrolled для этого поля. |
484
- | `segments` | `MainMenuSegment` | — | Сегменты правой панели (сетка карточек) — только каталог. <br/> При поиске: совпадения из сегментов без `pinBottomOnSearch` → `platformGroups` → сегменты с `pinBottomOnSearch`. <br/> Если один и тот же {@link InnerLink.id} совпал сразу в нескольких сегментах — остаётся только <br/> первое по этому приоритету вхождение, остальные (и опустевшие после этого группы) не показываются. <br/> При `segments.length > 1` показывается SegmentControl (скрывается во время поиска). <br/> Порядок и раскрытие групп — через `segmentPrefs` и колбэки ниже. |
485
- | `setOpen` | `((open: boolean) => void)` | — | |
486
- | `settingItems` | `InnerLink` \| `MainMenuSettingsItem` | — | Пункты левой колонки (desktop) / нижней части списка (mobile). <br/> Плоский список (`dividerBefore` для разделителей). <br/> Не связан с сегментами правой панели и не меняется при сортировке групп в сегментах. |
487
-
488
- ##### Related types
489
-
490
- **FavoriteProps**
491
-
492
- | Prop | Type | Default | Description |
493
- |------|------|---------|-------------|
494
- | `actions` | `BaseItemProps` | — | Действия для списка сервисов |
495
- | `loading` | `boolean \| undefined` | — | Флаг загрузки данных |
496
- | `onChange` | `(productId: string) => (addingValue: boolean, position?: number) => void` | — | Колбэк переключения избранного для карточки сервиса. <br/> `position` передаётся при добавлении через drag из сетки сервисов — индекс, <br/> на который должна встать карточка среди избранного (см. <br/> {@link <br/> FavoriteProps.onOrderChange <br/> } <br/> ). <br/> При переключении избранного кликом не передаётся. |
497
- | `onFavoriteServiceClick` | `((serviceId: string, event?: MouseEvent<HTMLElement>) => void) \| undefined` | — | Колбэк клика по карточке сервиса в сегменте «Избранное» |
498
- | `onOrderChange` | `((orderedIds: string[]) => void) \| undefined` | — | Колбэк вызывается после перетаскивания карточек внутри избранного с новым порядком id. <br/> Добавление новой карточки через drag из сетки сервисов идёт через <br/> {@link <br/> FavoriteProps.onChange <br/> } <br/> с `position` — этот колбэк для такого добавления не вызывается. |
499
- | `onRecentServiceClick` | `((serviceId: string, event?: MouseEvent<HTMLElement>) => void) \| undefined` | — | Колбэк клика по карточке сервиса в сегменте «Недавнее» |
500
- | `onSegmentChange` | `((segment: FavoritesSegment) => void) \| undefined` | — | Колбэк смены сегмента панели избранного. |
501
- | `recentServices` | `string[] \| undefined` | — | Список id недавно открытых сервисов |
502
- | `segment` | `"favorites"` \| `"recent"` | — | Активный сегмент («Избранное» / «Недавнее») в панели избранного. <br/> Не передано — неуправляемое состояние (дефолт `'favorites'`). |
503
- | `value` | `string[]` | — | Список id избранных сервисов |
504
-
505
- - `FavoritesSegment` = `"favorites"` \| `"recent"`
506
-
507
- **InnerLink**
508
-
509
- | Prop | Type | Default | Description |
510
- |------|------|---------|-------------|
511
- | `aliases` | `string[]` | — | Синонимы для fuzzy-поиска. |
512
- | `badge` | `CardServiceLightProps` \| `PromoTagPredefinedBaseProps` | — | |
513
- | `description` | `string \| undefined` | — | Краткое описание сервиса — отображается при включённом переключателе «Описание». |
514
- | `disabled` | `boolean \| undefined` | — | |
515
- | `hidden` | `boolean \| undefined` | — | |
516
- | `href` | `string \| undefined` | — | |
517
- | `icon` | `JSXElementConstructor<{ size?: number; className?: string; }> \| undefined` | — | Иконка карточки. |
518
- | `id` | `string` | — | Уникальный идентификатор карточки (также используется в избранном и при поиске). <br/> Один и тот же сервис может быть представлен в разных сегментах с разной <br/> детализацией (простая карточка в общем каталоге и раскрытая с вложенными <br/> сервисами версия в другом сегменте) — в этом случае обеим версиям задаётся <br/> общий `id`. При поиске из совпадений с одинаковым `id` в разных сегментах <br/> остаётся только первое по приоритету сегментов (см. <br/> {@link <br/> MainMenuProps.segments <br/> } <br/> ). |
519
- | `items` | `InnerLink` | — | Вложенные сервисы подкатегории. <br/> При наличии карточка раскрывается аккордеоном: в свёрнутом виде — обычная карточка <br/> с кнопкой раскрытия, в развёрнутом — заголовок <br/> {@link <br/> TitleClickable <br/> } <br/> и сетка вложенных сервисов. |
520
- | `label` | `string` | — | Заголовок карточки. |
521
- | `onClick` | `(e?: MouseEvent<HTMLElement>) => void` | — | |
522
-
523
- **LinksGroup**
524
-
525
- | Prop | Type | Default | Description |
526
- |------|------|---------|-------------|
527
- | `aliases` | `string[] \| undefined` | — | Синонимы заголовка группы для fuzzy-поиска. |
528
- | `blockColor` | `"blue"` \| `"green"` \| `"neutral"` \| `"orange"` \| `"pink"` \| `"primary"` \| `"red"` \| `"violet"` \| `"yellow"` | — | Цвет блока группы. |
529
- | `favoritesEnabled` | `boolean \| undefined` | — | Разрешено ли добавление карточек группы в избранное. |
530
- | `hidden` | `boolean \| undefined` | — | |
531
- | `highlight` | `boolean \| undefined` | — | Визуальное выделение группы |
532
- | `icon` | `JSXElementConstructor<{ size?: number; className?: string; }> \| undefined` | — | |
533
- | `id` | `string` | — | Уникальный идентификатор группы (якорь скролла, поиск по id). |
534
- | `items` | `InnerLink` | — | Карточки сервисов или ссылок внутри группы. |
535
- | `label` | `LinksGroupTitle` \| `TitleClickable` \| `TitleStatic` | — | Заголовок группы в сетке карточек и в боковой навигации. |
536
- | `onClick` | `((e?: MouseEvent<HTMLElement>) => void) \| undefined` | — | |
537
-
538
- - `LinksGroupBlockColor` = `"blue"` \| `"green"` \| `"neutral"` \| `"orange"` \| `"pink"` \| `"primary"` \| `"red"` \| `"violet"` \| `"yellow"`
539
-
540
- - `LinksGroupTitle` = `TitleStatic | TitleClickable`
541
-
542
- **MainMenuPreferencesProps**
543
-
544
- | Prop | Type | Default | Description |
545
- |------|------|---------|-------------|
546
- | `onOpenChange` | `((open: boolean) => void) \| undefined` | — | Колбэк открытия/закрытия модалки. |
547
- | `open` | `boolean \| undefined` | — | Открыта ли модалка настроек. <br/> Не передано — состояние открытия неуправляемое (модалка сама переключает себя по клику на кнопку). |
548
- | `showDescription` | `MainMenuToggleProps` | — | Показывать описания сервисов в карточках. |
549
- | `showGroupsColors` | `MainMenuToggleProps` | — | Отображать цвета блоков групп ( <br/> {@link <br/> LinksGroup.blockColor <br/> } <br/> ). <br/> `value: false` скрывает цвета всех групп независимо от заданного `blockColor`. |
550
-
551
- **MainMenuSegment**
552
-
553
- | Prop | Type | Default | Description |
554
- |------|------|---------|-------------|
555
- | `icon` | `string \| number \| boolean \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal \| null \| undefined` | — | Иконка сегмента в SegmentControl; без неё — только `label`. |
556
- | `id` | `string` | — | Уникальный идентификатор сегмента (значение SegmentControl). |
557
- | `items` | `LinksGroup` | — | Группы карточек сегмента (каталог). |
558
- | `label` | `string` | — | Подпись сегмента в SegmentControl. |
559
- | `pinBottomOnSearch` | `boolean \| undefined` | — | Группы сегмента в выдаче поиска — после совпадений из обычных сегментов и `platformGroups`. |
560
-
561
- **MainMenuSegmentPrefs**
562
-
563
- | Prop | Type | Default | Description |
564
- |------|------|---------|-------------|
565
- | `expanded` | `string[] \| undefined` | — | Id раскрытых групп. Если не передан — uncontrolled (по умолчанию все раскрыты). |
566
- | `id` | `string` | — | Id сегмента из <br/> {@link <br/> MainMenuSegment.id <br/> } <br/> . |
567
- | `order` | `string[] \| undefined` | — | Порядок id групп. Если не передан — uncontrolled для этого сегмента <br/> (дефолт = порядок `items`; новые группы добавляются в конец). |
568
-
569
- **MainMenuSettingsItem**
570
-
571
- | Prop | Type | Default | Description |
572
- |------|------|---------|-------------|
573
- | `divider` | `"after"` \| `"before"` | — | |
574
- | `hidden` | `boolean \| undefined` | — | |
575
- | `href` | `string \| undefined` | — | |
576
- | `icon` | `JSXElementConstructor<{ size?: number; className?: string; }> \| undefined` | — | Иконка карточки. |
577
- | `id` | `string` | — | Уникальный идентификатор карточки (также используется в избранном и при поиске). <br/> Один и тот же сервис может быть представлен в разных сегментах с разной <br/> детализацией (простая карточка в общем каталоге и раскрытая с вложенными <br/> сервисами версия в другом сегменте) — в этом случае обеим версиям задаётся <br/> общий `id`. При поиске из совпадений с одинаковым `id` в разных сегментах <br/> остаётся только первое по приоритету сегментов (см. <br/> {@link <br/> MainMenuProps.segments <br/> } <br/> ). |
578
- | `label` | `string` | — | Заголовок карточки. |
579
- | `onClick` | `(e?: MouseEvent<HTMLElement>) => void` | — | |
580
-
581
- **MainMenuToggleProps**
582
-
583
- | Prop | Type | Default | Description |
584
- |------|------|---------|-------------|
585
- | `onChange` | `(value: boolean) => void` | — | |
586
- | `value` | `boolean` | — | |
587
-
588
- **SearchProps**
589
-
590
- | Prop | Type | Default | Description |
591
- |------|------|---------|-------------|
592
- | `onBlur` | `FocusEventHandler<HTMLInputElement> \| undefined` | — | Колбек обработки потери фокуса |
593
- | `onChange` | `(value: string) => void` | — | |
594
- | `onFocus` | `FocusEventHandler<HTMLInputElement> \| undefined` | — | Колбек обработки получения фокуса |
595
- | `onSearchNoResult` | `((value: string) => void) \| undefined` | — | |
596
- | `value` | `string` | — | |
597
-
598
- **TitleClickable**
599
-
600
- | Prop | Type | Default | Description |
601
- |------|------|---------|-------------|
602
- | `href` | `string \| undefined` | — | |
603
- | `onClick` | `((e?: MouseEvent<HTMLElement>) => void) \| undefined` | — | |
604
- | `text` | `string` | — | |
605
-
606
- **TitleStatic**
607
-
608
- | Prop | Type | Default | Description |
609
- |------|------|---------|-------------|
610
- | `href` | `undefined` | — | |
611
- | `onClick` | `undefined` | — | |
612
- | `text` | `string` | — | |
613
-
614
- ### Адаптивность
615
-
616
- | Проп / поведение | Desktop | Mobile |
617
- | --- | --- | --- |
618
- | Drawer | Resizable слева | Fullscreen bottom sheet |
619
- | `favorite` DnD | Да | Нет |
620
- | `segments` / `SegmentControl` | Да | Да (скрывается при поиске) |
621
- | `preferences` | Модалка настроек в тулбаре | То же |
622
-
623
356
  ## UserMenu
624
357
 
625
358
  Меню пользователя — профиль, переключатель темы, пункты настроек и выход.
@@ -14,11 +14,12 @@ const utils_1 = require("../../utils");
14
14
  const styles_module_scss_1 = __importDefault(require('./styles.module.css'));
15
15
  function ServiceCard({ service, favorite, isMobile, onServiceClick, showDescription, className, tabIndex, dragPreview, expandable, }) {
16
16
  const isInFavorites = favorite?.value.includes(service.id) ?? false;
17
+ const isFavoriteEnabled = service.favoritesEnabled ?? true;
17
18
  const favoriteProps = !dragPreview && favorite
18
19
  ? {
19
20
  checked: isInFavorites,
20
21
  onChange: favorite.onChange(service.id),
21
- enabled: !service.disabled,
22
+ enabled: !service.disabled && isFavoriteEnabled,
22
23
  }
23
24
  : undefined;
24
25
  const commonProps = {
@@ -43,7 +44,8 @@ function ServiceCard({ service, favorite, isMobile, onServiceClick, showDescript
43
44
  return dragPreview ? (0, jsx_runtime_1.jsx)(drag_and_drop_1.DragPreview, { className: styles_module_scss_1.default.dragCardPreview, children: card }) : card;
44
45
  }
45
46
  function DraggableServiceCard({ groupId, service, favorite, dragDisabled, ...props }) {
46
- const disabled = dragDisabled || service.disabled || favorite?.value.includes(service.id);
47
+ const isFavoriteEnabled = service.favoritesEnabled ?? true;
48
+ const disabled = dragDisabled || service.disabled || favorite?.value.includes(service.id) || !isFavoriteEnabled;
47
49
  const { attributes, listeners, setNodeRef, isDragging } = (0, core_1.useDraggable)({
48
50
  id: (0, utils_1.getServiceSourceDragId)(groupId, service.id),
49
51
  disabled,
@@ -1,5 +1,4 @@
1
1
  export * from './MainMenu';
2
- export { MenuMobile } from './helperComponents/MenuMobile';
3
2
  export * from './helperComponents/Banners';
4
3
  export * from './helperComponents/Favorites';
5
4
  export * from './types';
@@ -14,10 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.MenuMobile = void 0;
18
17
  __exportStar(require("./MainMenu"), exports);
19
- var MenuMobile_1 = require("./helperComponents/MenuMobile");
20
- Object.defineProperty(exports, "MenuMobile", { enumerable: true, get: function () { return MenuMobile_1.MenuMobile; } });
21
18
  __exportStar(require("./helperComponents/Banners"), exports);
22
19
  __exportStar(require("./helperComponents/Favorites"), exports);
23
20
  __exportStar(require("./types"), exports);
@@ -34,6 +34,8 @@ export type InnerLink = {
34
34
  disabled?: boolean;
35
35
  hidden?: boolean;
36
36
  badge?: CardServiceLightProps['promoTag'];
37
+ /** Разрешено ли добавление карточки в избранное. default=true - разрешено */
38
+ favoritesEnabled?: boolean;
37
39
  /**
38
40
  * Вложенные сервисы подкатегории.
39
41
  *
@@ -7,11 +7,12 @@ import { getLinkEmblem, getServiceSourceDragId } from '../../utils/index.js';
7
7
  import styles from './styles.module.css';
8
8
  export function ServiceCard({ service, favorite, isMobile, onServiceClick, showDescription, className, tabIndex, dragPreview, expandable, }) {
9
9
  const isInFavorites = favorite?.value.includes(service.id) ?? false;
10
+ const isFavoriteEnabled = service.favoritesEnabled ?? true;
10
11
  const favoriteProps = !dragPreview && favorite
11
12
  ? {
12
13
  checked: isInFavorites,
13
14
  onChange: favorite.onChange(service.id),
14
- enabled: !service.disabled,
15
+ enabled: !service.disabled && isFavoriteEnabled,
15
16
  }
16
17
  : undefined;
17
18
  const commonProps = {
@@ -36,7 +37,8 @@ export function ServiceCard({ service, favorite, isMobile, onServiceClick, showD
36
37
  return dragPreview ? _jsx(DragPreview, { className: styles.dragCardPreview, children: card }) : card;
37
38
  }
38
39
  export function DraggableServiceCard({ groupId, service, favorite, dragDisabled, ...props }) {
39
- const disabled = dragDisabled || service.disabled || favorite?.value.includes(service.id);
40
+ const isFavoriteEnabled = service.favoritesEnabled ?? true;
41
+ const disabled = dragDisabled || service.disabled || favorite?.value.includes(service.id) || !isFavoriteEnabled;
40
42
  const { attributes, listeners, setNodeRef, isDragging } = useDraggable({
41
43
  id: getServiceSourceDragId(groupId, service.id),
42
44
  disabled,
@@ -1,5 +1,4 @@
1
1
  export * from './MainMenu.js';
2
- export { MenuMobile } from './helperComponents/MenuMobile/index.js';
3
2
  export * from './helperComponents/Banners/index.js';
4
3
  export * from './helperComponents/Favorites/index.js';
5
4
  export * from './types.js';
@@ -1,5 +1,4 @@
1
1
  export * from './MainMenu.js';
2
- export { MenuMobile } from './helperComponents/MenuMobile/index.js';
3
2
  export * from './helperComponents/Banners/index.js';
4
3
  export * from './helperComponents/Favorites/index.js';
5
4
  export * from './types.js';
@@ -34,6 +34,8 @@ export type InnerLink = {
34
34
  disabled?: boolean;
35
35
  hidden?: boolean;
36
36
  badge?: CardServiceLightProps['promoTag'];
37
+ /** Разрешено ли добавление карточки в избранное. default=true - разрешено */
38
+ favoritesEnabled?: boolean;
37
39
  /**
38
40
  * Вложенные сервисы подкатегории.
39
41
  *