@cloud-ru/ds-uikit-product-header 2.1.4-preview-20b4671f.0 → 2.1.4

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 (56) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +2 -0
  3. package/dist/cjs/components/MainMenu/MainMenu.d.ts +1 -1
  4. package/dist/cjs/components/MainMenu/MainMenu.js +2 -2
  5. package/dist/cjs/components/MainMenu/helperComponents/Banners/styles.module.css +1 -0
  6. package/dist/cjs/components/MainMenu/helperComponents/Content/Content.d.ts +5 -1
  7. package/dist/cjs/components/MainMenu/helperComponents/Content/Content.js +4 -3
  8. package/dist/cjs/components/MainMenu/helperComponents/Content/helperComponents/SortableGroup/components/SortableGroupDragHandle.d.ts +1 -8
  9. package/dist/cjs/components/MainMenu/helperComponents/Content/helperComponents/SortableGroup/components/SortableGroupDragHandle.js +2 -2
  10. package/dist/cjs/components/MainMenu/helperComponents/Content/helperComponents/SortableGroup/components/SortableGroupHeader.d.ts +6 -2
  11. package/dist/cjs/components/MainMenu/helperComponents/Content/helperComponents/SortableGroup/components/SortableGroupHeader.js +1 -1
  12. package/dist/cjs/components/MainMenu/helperComponents/Content/helperComponents/SortableGroup/styles.module.css +13 -10
  13. package/dist/cjs/components/MainMenu/helperComponents/Content/styles.module.css +15 -0
  14. package/dist/cjs/components/MainMenu/helperComponents/MenuDesktop/MenuDesktop.d.ts +1 -1
  15. package/dist/cjs/components/MainMenu/helperComponents/MenuDesktop/MenuDesktop.js +4 -4
  16. package/dist/cjs/components/MainMenu/helperComponents/MenuDesktop/constants.d.ts +1 -1
  17. package/dist/cjs/components/MainMenu/helperComponents/MenuDesktop/constants.js +3 -3
  18. package/dist/cjs/components/MainMenu/hooks/useMainMenuDnd.js +12 -0
  19. package/dist/cjs/components/MainMenu/styles.module.css +8 -0
  20. package/dist/cjs/components/MainMenu/types.d.ts +1 -1
  21. package/dist/cjs/style.css +37 -10
  22. package/dist/esm/components/MainMenu/MainMenu.d.ts +1 -1
  23. package/dist/esm/components/MainMenu/MainMenu.js +2 -2
  24. package/dist/esm/components/MainMenu/helperComponents/Banners/styles.module.css +1 -0
  25. package/dist/esm/components/MainMenu/helperComponents/Content/Content.d.ts +5 -1
  26. package/dist/esm/components/MainMenu/helperComponents/Content/Content.js +4 -3
  27. package/dist/esm/components/MainMenu/helperComponents/Content/helperComponents/SortableGroup/components/SortableGroupDragHandle.d.ts +1 -8
  28. package/dist/esm/components/MainMenu/helperComponents/Content/helperComponents/SortableGroup/components/SortableGroupDragHandle.js +2 -2
  29. package/dist/esm/components/MainMenu/helperComponents/Content/helperComponents/SortableGroup/components/SortableGroupHeader.d.ts +6 -2
  30. package/dist/esm/components/MainMenu/helperComponents/Content/helperComponents/SortableGroup/components/SortableGroupHeader.js +1 -1
  31. package/dist/esm/components/MainMenu/helperComponents/Content/helperComponents/SortableGroup/styles.module.css +13 -10
  32. package/dist/esm/components/MainMenu/helperComponents/Content/styles.module.css +15 -0
  33. package/dist/esm/components/MainMenu/helperComponents/MenuDesktop/MenuDesktop.d.ts +1 -1
  34. package/dist/esm/components/MainMenu/helperComponents/MenuDesktop/MenuDesktop.js +5 -5
  35. package/dist/esm/components/MainMenu/helperComponents/MenuDesktop/constants.d.ts +1 -1
  36. package/dist/esm/components/MainMenu/helperComponents/MenuDesktop/constants.js +2 -2
  37. package/dist/esm/components/MainMenu/hooks/useMainMenuDnd.js +10 -1
  38. package/dist/esm/components/MainMenu/styles.module.css +8 -0
  39. package/dist/esm/components/MainMenu/types.d.ts +1 -1
  40. package/dist/esm/style.css +37 -10
  41. package/dist/tsconfig.cjs.tsbuildinfo +1 -1
  42. package/dist/tsconfig.esm.tsbuildinfo +1 -1
  43. package/package.json +28 -28
  44. package/src/components/MainMenu/MainMenu.tsx +2 -0
  45. package/src/components/MainMenu/helperComponents/Banners/styles.module.scss +1 -0
  46. package/src/components/MainMenu/helperComponents/Content/Content.tsx +12 -2
  47. package/src/components/MainMenu/helperComponents/Content/helperComponents/SortableGroup/components/SortableGroupDragHandle.tsx +1 -11
  48. package/src/components/MainMenu/helperComponents/Content/helperComponents/SortableGroup/components/SortableGroupHeader.tsx +9 -4
  49. package/src/components/MainMenu/helperComponents/Content/helperComponents/SortableGroup/styles.module.scss +27 -19
  50. package/src/components/MainMenu/helperComponents/Content/styles.module.scss +22 -0
  51. package/src/components/MainMenu/helperComponents/MenuDesktop/MenuDesktop.tsx +6 -4
  52. package/src/components/MainMenu/helperComponents/MenuDesktop/constants.ts +2 -2
  53. package/src/components/MainMenu/helperComponents/MenuDesktop/styles.module.scss +6 -2
  54. package/src/components/MainMenu/hooks/useMainMenuDnd.tsx +12 -1
  55. package/src/components/MainMenu/styles.module.scss +10 -0
  56. package/src/components/MainMenu/types.ts +1 -0
package/CHANGELOG.md CHANGED
@@ -3,6 +3,12 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## 2.1.4 (2026-10-09)
7
+
8
+ ### Bug Fixes
9
+
10
+ - **FF-9241:** resize navigation menu, category drag by whole title, expose onToggleAllGroupsExpanded prop ([c6cc467](https://github.com/cloud-ru-tech/snack-v2/commit/c6cc467b7b44789f1c3b9022a9bf85478dafb815))
11
+
6
12
  ## 2.1.3 (2026-10-06)
7
13
 
8
14
  **Note:** Version bump only for package @ds/uikit-product-header
package/README.md CHANGED
@@ -303,6 +303,7 @@ function LocalMainMenu() {
303
303
  | `onSegmentExpandedChange` | `((segmentId: string, expandedGroupIds: string[]) => void)` | — | Колбэк при изменении набора раскрытых групп сегмента <br/> (без id синтетической группы избранного). |
304
304
  | `onSegmentOrderChange` | `((segmentId: string, orderedGroupIds: string[]) => void)` | — | Колбэк после DnD групп в сегменте (без id синтетической группы избранного). |
305
305
  | `onSegmentServiceClick` | `((service: InnerLink, e?: MouseEvent<HTMLElement, MouseEvent>) => void)` | — | Колбэк клика по карточке сервиса в сегменте. |
306
+ | `onToggleAllGroupsExpanded` | `((action: "collapseAll" \| "expandAll") => void)` | — | Колбэк смены всех групп раскрытых. |
306
307
  | `onWidthChangeEnd` | `((width: number) => void)` | — | Вызывается при окончании изменения ширины дровера (desktop only) |
307
308
  | `open` | `boolean` | — | Открыто ли меню. <br/> Не передано — состояние открытия неуправляемое (меню само переключает себя по клику на кнопку). |
308
309
  | `platformGroups` | `LinksGroup` | — | Платформенные группы (например «Облачные продукты», «Другие продукты»). <br/> Без поиска в сетке карточек **не отображаются**. <br/> С поиском: попадают в результаты при совпадении; порядок — <br/> после совпадений из сегментов без `pinBottomOnSearch`, перед сегментами с `pinBottomOnSearch`. <br/> Обычно `favoritesEnabled: false`; карточки могут быть без `icon` (Avatar по `label`). |
@@ -477,6 +478,7 @@ import { MainMenu, MenuMobile } from '@cloud-ru/ds-uikit-product-header';
477
478
  | `onSegmentExpandedChange` | `((segmentId: string, expandedGroupIds: string[]) => void)` | — | Колбэк при изменении набора раскрытых групп сегмента <br/> (без id синтетической группы избранного). |
478
479
  | `onSegmentOrderChange` | `((segmentId: string, orderedGroupIds: string[]) => void)` | — | Колбэк после DnD групп в сегменте (без id синтетической группы избранного). |
479
480
  | `onSegmentServiceClick` | `((service: InnerLink, e?: MouseEvent<HTMLElement, MouseEvent>) => void)` | — | Колбэк клика по карточке сервиса в сегменте. |
481
+ | `onToggleAllGroupsExpanded` | `((action: "collapseAll" \| "expandAll") => void)` | — | Колбэк смены всех групп раскрытых. |
480
482
  | `onWidthChangeEnd` | `((width: number) => void)` | — | Вызывается при окончании изменения ширины дровера (desktop only) |
481
483
  | `open` | `boolean` | `false` | Открыто ли меню. <br/> Не передано — состояние открытия неуправляемое (меню само переключает себя по клику на кнопку). |
482
484
  | `platformGroups` | `LinksGroup` | — | Платформенные группы (например «Облачные продукты», «Другие продукты»). <br/> Без поиска в сетке карточек **не отображаются**. <br/> С поиском: попадают в результаты при совпадении; порядок — <br/> после совпадений из сегментов без `pinBottomOnSearch`, перед сегментами с `pinBottomOnSearch`. <br/> Обычно `favoritesEnabled: false`; карточки могут быть без `icon` (Avatar по `label`). |
@@ -1,2 +1,2 @@
1
1
  import { MainMenuProps } from './types';
2
- export declare function MainMenu({ open: openProp, setOpen: setOpenProp, settingItems, platformGroups, logo, leftTop, leftBottom, rightTop, segments, segmentPrefs, activeSegmentId, onActiveSegmentChange, onSegmentOrderChange, onSegmentExpandedChange, onSegmentServiceClick, favorite, search, preferences, disabled, defaultWidth, onWidthChangeEnd, draggerTooltip, loading, }: MainMenuProps): import("react/jsx-runtime").JSX.Element;
2
+ export declare function MainMenu({ open: openProp, setOpen: setOpenProp, settingItems, platformGroups, logo, leftTop, leftBottom, rightTop, segments, segmentPrefs, activeSegmentId, onActiveSegmentChange, onSegmentOrderChange, onSegmentExpandedChange, onToggleAllGroupsExpanded, onSegmentServiceClick, favorite, search, preferences, disabled, defaultWidth, onWidthChangeEnd, draggerTooltip, loading, }: MainMenuProps): import("react/jsx-runtime").JSX.Element;
@@ -11,7 +11,7 @@ const locale_1 = require("../../locale");
11
11
  const HeaderButton_1 = require("../HeaderButton");
12
12
  const MenuDesktop_1 = require("./helperComponents/MenuDesktop");
13
13
  const MenuMobile_1 = require("./helperComponents/MenuMobile");
14
- function MainMenu({ open: openProp, setOpen: setOpenProp, settingItems, platformGroups, logo, leftTop, leftBottom, rightTop, segments, segmentPrefs, activeSegmentId, onActiveSegmentChange, onSegmentOrderChange, onSegmentExpandedChange, onSegmentServiceClick, favorite, search, preferences, disabled, defaultWidth, onWidthChangeEnd, draggerTooltip, loading, }) {
14
+ function MainMenu({ open: openProp, setOpen: setOpenProp, settingItems, platformGroups, logo, leftTop, leftBottom, rightTop, segments, segmentPrefs, activeSegmentId, onActiveSegmentChange, onSegmentOrderChange, onSegmentExpandedChange, onToggleAllGroupsExpanded, onSegmentServiceClick, favorite, search, preferences, disabled, defaultWidth, onWidthChangeEnd, draggerTooltip, loading, }) {
15
15
  const { t } = locale_1.headerLocale.useTranslations();
16
16
  const [open = false, setOpen] = (0, utils_1.useValueControl)({ value: openProp, onChange: setOpenProp });
17
17
  const searchValue = search?.value;
@@ -25,5 +25,5 @@ function MainMenu({ open: openProp, setOpen: setOpenProp, settingItems, platform
25
25
  }, [setOpen]);
26
26
  const isMobile = (0, useMobileLayout_1.useMobileLayout)();
27
27
  const MenuComponent = isMobile ? MenuMobile_1.MenuMobile : MenuDesktop_1.MenuDesktop;
28
- return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(HeaderButton_1.HeaderButton, { tooltip: open ? undefined : { tip: t('services') }, isMobile: isMobile, disabled: disabled, icon: (0, jsx_runtime_1.jsx)(product_1.MainMenuSVG, {}), onClick: handleOpen, "data-test-id": constants_1.TEST_IDS.mainMenu.drawerButton }), (0, jsx_runtime_1.jsx)(MenuComponent, { settingItems: settingItems, segments: segments, segmentPrefs: segmentPrefs, activeSegmentId: activeSegmentId, onActiveSegmentChange: onActiveSegmentChange, onSegmentOrderChange: onSegmentOrderChange, onSegmentExpandedChange: onSegmentExpandedChange, onSegmentServiceClick: onSegmentServiceClick, platformGroups: platformGroups, search: search, logo: logo, leftTop: leftTop, leftBottom: leftBottom, rightTop: rightTop, favorite: favorite, open: open, setOpen: setOpen, preferences: preferences, defaultWidth: defaultWidth, onWidthChangeEnd: onWidthChangeEnd, draggerTooltip: draggerTooltip, loading: loading })] }));
28
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(HeaderButton_1.HeaderButton, { tooltip: open ? undefined : { tip: t('services') }, isMobile: isMobile, disabled: disabled, icon: (0, jsx_runtime_1.jsx)(product_1.MainMenuSVG, {}), onClick: handleOpen, "data-test-id": constants_1.TEST_IDS.mainMenu.drawerButton }), (0, jsx_runtime_1.jsx)(MenuComponent, { settingItems: settingItems, segments: segments, segmentPrefs: segmentPrefs, activeSegmentId: activeSegmentId, onActiveSegmentChange: onActiveSegmentChange, onSegmentOrderChange: onSegmentOrderChange, onSegmentExpandedChange: onSegmentExpandedChange, onSegmentServiceClick: onSegmentServiceClick, onToggleAllGroupsExpanded: onToggleAllGroupsExpanded, platformGroups: platformGroups, search: search, logo: logo, leftTop: leftTop, leftBottom: leftBottom, rightTop: rightTop, favorite: favorite, open: open, setOpen: setOpen, preferences: preferences, defaultWidth: defaultWidth, onWidthChangeEnd: onWidthChangeEnd, draggerTooltip: draggerTooltip, loading: loading })] }));
29
29
  }
@@ -70,4 +70,5 @@
70
70
 
71
71
  .promoTag{
72
72
  cursor:inherit;
73
+ flex-shrink:0;
73
74
  }
@@ -36,6 +36,10 @@ export type ContentProps = {
36
36
  * (без id синтетической группы избранного).
37
37
  */
38
38
  onSegmentExpandedChange?(segmentId: string, expandedGroupIds: string[]): void;
39
+ /**
40
+ * Колбэк смены всех групп раскрытых.
41
+ */
42
+ onToggleAllGroupsExpanded?(action: 'collapseAll' | 'expandAll'): void;
39
43
  /**
40
44
  * Колбэк клика по карточке сервиса в сегменте.
41
45
  */
@@ -63,4 +67,4 @@ export type ContentProps = {
63
67
  /** Флаг загрузки данных */
64
68
  loading?: boolean;
65
69
  };
66
- export declare function Content({ searchValue, search, rightTop, segments, searchGroups, segmentPrefs, activeSegmentId, onActiveSegmentChange, onSegmentOrderChange, onSegmentExpandedChange, onSegmentServiceClick, className, footer, favorite, isMobile, preferences, loading, }: ContentProps): import("react/jsx-runtime").JSX.Element;
70
+ export declare function Content({ searchValue, search, rightTop, segments, searchGroups, segmentPrefs, activeSegmentId, onActiveSegmentChange, onSegmentOrderChange, onSegmentExpandedChange, onSegmentServiceClick, onToggleAllGroupsExpanded, className, footer, favorite, isMobile, preferences, loading, }: ContentProps): import("react/jsx-runtime").JSX.Element;
@@ -26,7 +26,7 @@ const useContentSegmentsSortable_1 = require("./hooks/useContentSegmentsSortable
26
26
  const useProgressiveCount_1 = require("./hooks/useProgressiveCount");
27
27
  const useSegmentDnd_1 = require("./hooks/useSegmentDnd");
28
28
  const styles_module_scss_1 = __importDefault(require('./styles.module.css'));
29
- function Content({ searchValue, search, rightTop, segments, searchGroups = emptyArray_1.EMPTY_ARRAY, segmentPrefs, activeSegmentId, onActiveSegmentChange, onSegmentOrderChange, onSegmentExpandedChange, onSegmentServiceClick, className, footer, favorite, isMobile, preferences, loading, }) {
29
+ function Content({ searchValue, search, rightTop, segments, searchGroups = emptyArray_1.EMPTY_ARRAY, segmentPrefs, activeSegmentId, onActiveSegmentChange, onSegmentOrderChange, onSegmentExpandedChange, onSegmentServiceClick, onToggleAllGroupsExpanded, className, footer, favorite, isMobile, preferences, loading, }) {
30
30
  const { t } = locale_1.headerLocale.useTranslations();
31
31
  const showDescription = (0, react_1.useDeferredValue)(preferences?.showDescription.value ?? false);
32
32
  const segmentPrefsById = (0, react_1.useMemo)(() => new Map((segmentPrefs ?? []).map(prefs => [prefs.id, prefs])), [segmentPrefs]);
@@ -82,13 +82,14 @@ function Content({ searchValue, search, rightTop, segments, searchGroups = empty
82
82
  const visibleGroupIds = (0, react_1.useMemo)(() => visibleGroups.map(({ id }) => id), [visibleGroups]);
83
83
  const allGroupsExpanded = visibleGroups.length > 0 && visibleGroupIds.every(id => expandedIdsSet.has(id));
84
84
  const handleToggleAllGroupsExpanded = (0, react_1.useCallback)(() => {
85
+ onToggleAllGroupsExpanded?.(allGroupsExpanded ? 'collapseAll' : 'expandAll');
85
86
  if (allGroupsExpanded) {
86
87
  const visibleIdsSet = new Set(visibleGroupIds);
87
88
  onExpandedChange(expandedIds.filter(id => !visibleIdsSet.has(id)));
88
89
  return;
89
90
  }
90
91
  onExpandedChange([...new Set([...expandedIds, ...visibleGroupIds])]);
91
- }, [allGroupsExpanded, expandedIds, onExpandedChange, visibleGroupIds]);
92
+ }, [allGroupsExpanded, expandedIds, onExpandedChange, visibleGroupIds, onToggleAllGroupsExpanded]);
92
93
  const cardsContext = (0, react_1.useMemo)(() => ({
93
94
  showDescription,
94
95
  isMobile,
@@ -116,5 +117,5 @@ function Content({ searchValue, search, rightTop, segments, searchGroups = empty
116
117
  appearance: 'neutral',
117
118
  }, content: isSearching ? t('noDataFound') : t('noData'), "data-test-id": isSearching ? constants_1.TEST_IDS.noDataFound : constants_1.TEST_IDS.noData, "data-mobile": isMobile || undefined, className: styles_module_scss_1.default.noData }));
118
119
  })();
119
- return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [search, (0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)(styles_module_scss_1.default.content, className), "data-mobile": isMobile || undefined, "data-empty": (!loading && !hasCards) || undefined, children: [!isSearching && ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: (0, jsx_runtime_1.jsxs)(MountAnimation_1.MountAnimation, { type: mountAnimationType, className: styles_module_scss_1.default.top, children: [(0, jsx_runtime_1.jsx)(ContentToolbar_1.ContentToolbar, { segment: segmentId, onSegmentChange: setSegmentId, segmentItems: segmentItems, allGroupsExpanded: allGroupsExpanded, onToggleAllGroupsExpanded: handleToggleAllGroupsExpanded, preferences: preferences, isMobile: isMobile, loading: loading }), rightTop] }) })), cards, footer] })] }));
120
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [search, (0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)(styles_module_scss_1.default.content, className), "data-mobile": isMobile || undefined, "data-empty": (!loading && !hasCards) || undefined, children: [!isSearching && ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: (0, jsx_runtime_1.jsxs)(MountAnimation_1.MountAnimation, { type: mountAnimationType, className: styles_module_scss_1.default.top, children: [(0, jsx_runtime_1.jsx)(ContentToolbar_1.ContentToolbar, { segment: segmentId, onSegmentChange: setSegmentId, segmentItems: segmentItems, allGroupsExpanded: allGroupsExpanded, onToggleAllGroupsExpanded: handleToggleAllGroupsExpanded, preferences: preferences, isMobile: isMobile, loading: loading }), (0, jsx_runtime_1.jsx)("div", { className: styles_module_scss_1.default.rightTop, "data-mobile": isMobile || undefined, children: rightTop })] }) })), cards, footer] })] }));
120
121
  }
@@ -1,8 +1 @@
1
- import { DraggableAttributes, DraggableSyntheticListeners } from '@dnd-kit/core';
2
- export type SortableGroupDragHandleProps = {
3
- /** ARIA-атрибуты `dnd-kit` draggable-элемента. */
4
- attributes?: DraggableAttributes;
5
- /** Обработчики событий `dnd-kit` для инициации перетаскивания. */
6
- listeners?: DraggableSyntheticListeners;
7
- };
8
- export declare function SortableGroupDragHandle({ attributes, listeners }: SortableGroupDragHandleProps): import("react/jsx-runtime").JSX.Element;
1
+ export declare function SortableGroupDragHandle(): import("react/jsx-runtime").JSX.Element;
@@ -9,7 +9,7 @@ const system_1 = require("@cloud-ru/ds-icons/interface/system");
9
9
  const utils_1 = require("@cloud-ru/ds-utils");
10
10
  const locale_1 = require("../../../../../../../locale");
11
11
  const styles_module_scss_1 = __importDefault(require('../styles.module.css'));
12
- function SortableGroupDragHandle({ attributes, listeners }) {
12
+ function SortableGroupDragHandle() {
13
13
  const { t } = locale_1.headerLocale.useTranslations();
14
- return ((0, jsx_runtime_1.jsx)("button", { ...attributes, ...listeners, type: 'button', className: styles_module_scss_1.default.dragHandle, "aria-label": t('dragGroup'), "data-test-id": 'header__drawer-menu__group-card-drag-handle', onClick: utils_1.stopEventPropagation, children: (0, jsx_runtime_1.jsx)(system_1.DragDropSVG, { size: 24 }) }));
14
+ return ((0, jsx_runtime_1.jsx)("button", { type: 'button', className: styles_module_scss_1.default.dragHandle, "aria-label": t('dragGroup'), "data-test-id": 'header__drawer-menu__group-card-drag-handle', onClick: utils_1.stopEventPropagation, children: (0, jsx_runtime_1.jsx)(system_1.DragDropSVG, { size: 24 }) }));
15
15
  }
@@ -1,11 +1,15 @@
1
+ import { DraggableAttributes, DraggableSyntheticListeners } from '@dnd-kit/core';
1
2
  import { LinksGroup, LinksGroupTitle } from '../../../../../types';
2
- import { SortableGroupDragHandleProps } from './SortableGroupDragHandle';
3
3
  export type SortableGroupHeaderProps = Pick<LinksGroup, 'icon'> & {
4
4
  label: LinksGroupTitle;
5
5
  isExpanded?: boolean;
6
6
  enableServiceDrag?: boolean;
7
7
  isMobile?: boolean;
8
- } & SortableGroupDragHandleProps;
8
+ /** ARIA-атрибуты `dnd-kit` draggable-элемента. */
9
+ attributes?: DraggableAttributes;
10
+ /** Обработчики событий `dnd-kit` для инициации перетаскивания. */
11
+ listeners?: DraggableSyntheticListeners;
12
+ };
9
13
  declare function SortableGroupHeaderBase({ label, icon, isExpanded, enableServiceDrag, attributes, listeners, isMobile, }: SortableGroupHeaderProps): import("react/jsx-runtime").JSX.Element;
10
14
  export declare const SortableGroupHeader: import("react").MemoExoticComponent<typeof SortableGroupHeaderBase>;
11
15
  export {};
@@ -18,6 +18,6 @@ function SortableGroupHeaderBase({ label, icon, isExpanded, enableServiceDrag, a
18
18
  e.stopPropagation();
19
19
  label?.onClick?.(e);
20
20
  }, [label]);
21
- return ((0, jsx_runtime_1.jsxs)("div", { className: styles_module_scss_1.default.header, "data-expanded": isExpanded || undefined, children: [(0, jsx_runtime_1.jsx)(typography_1.Typography, { variant: 'title', size: 'm', className: styles_module_scss_1.default.headerTitle, "data-test-id": 'header__drawer-menu__group-card-title', children: label.onClick || label.href ? ((0, jsx_runtime_1.jsx)(uikit_product_title_clickable_1.TitleClickable, { ...(label.href ? { as: 'a', href: label.href } : { as: 'div' }), onClick: handleLabelClick, title: label.text, icon: (0, utils_1.getLinkEmblem)({ icon }) })) : (label.text) }), (enableServiceDrag || !isMobile) && ((0, jsx_runtime_1.jsxs)("div", { className: styles_module_scss_1.default.headerActions, "data-always-visible": isMobile || undefined, children: [enableServiceDrag && (0, jsx_runtime_1.jsx)(SortableGroupDragHandle_1.SortableGroupDragHandle, { attributes: attributes, listeners: listeners }), !isMobile && ((0, jsx_runtime_1.jsx)(button_1.Button, { view: 'elevated', appearance: 'neutral', size: 's', icon: isExpanded ? (0, jsx_runtime_1.jsx)(system_1.ChevronUpSVG, {}) : (0, jsx_runtime_1.jsx)(system_1.ChevronDownSVG, {}), "data-test-id": 'header__drawer-menu__group-card-collapse' }))] }))] }));
21
+ return ((0, jsx_runtime_1.jsxs)("div", { className: styles_module_scss_1.default.header, "data-expanded": isExpanded || undefined, ...attributes, ...listeners, tabIndex: -1, children: [(0, jsx_runtime_1.jsx)(typography_1.Typography, { variant: 'title', size: 'm', className: styles_module_scss_1.default.headerTitle, "data-test-id": 'header__drawer-menu__group-card-title', children: label.onClick || label.href ? ((0, jsx_runtime_1.jsx)(uikit_product_title_clickable_1.TitleClickable, { ...(label.href ? { as: 'a', href: label.href } : { as: 'div' }), onClick: handleLabelClick, title: label.text, icon: (0, utils_1.getLinkEmblem)({ icon }) })) : (label.text) }), (enableServiceDrag || !isMobile) && ((0, jsx_runtime_1.jsxs)("div", { className: styles_module_scss_1.default.headerActions, "data-always-visible": isMobile || undefined, children: [enableServiceDrag && (0, jsx_runtime_1.jsx)(SortableGroupDragHandle_1.SortableGroupDragHandle, {}), !isMobile && ((0, jsx_runtime_1.jsx)(button_1.Button, { view: 'elevated', appearance: 'neutral', size: 's', icon: isExpanded ? (0, jsx_runtime_1.jsx)(system_1.ChevronUpSVG, {}) : (0, jsx_runtime_1.jsx)(system_1.ChevronDownSVG, {}), "data-test-id": 'header__drawer-menu__group-card-collapse' }))] }))] }));
22
22
  }
23
23
  exports.SortableGroupHeader = (0, react_1.memo)(SortableGroupHeaderBase);
@@ -8,6 +8,7 @@
8
8
  outline:none;
9
9
  }
10
10
  .headerActions[data-always-visible]{
11
+ pointer-events:auto;
11
12
  opacity:1;
12
13
  }
13
14
 
@@ -63,20 +64,25 @@
63
64
  animation:none;
64
65
  }
65
66
  }
66
- .group[data-drag-preview]{
67
- cursor:grabbing;
68
- }
69
67
  .group[data-drag-preview] .header{
70
- cursor:grabbing;
71
68
  background-color:var(--sn-theme-color-neutral-decorTransparent, var(--sn-brand-color-neutral-transparent-forLightMode, rgba(136, 146, 170, 0.0784313725)));
72
69
  }
73
70
  .group[data-drag-preview] .header .headerActions{
74
71
  pointer-events:auto;
75
72
  opacity:1;
76
73
  }
74
+ .group:has(:focus-visible) .headerActions{
75
+ pointer-events:auto;
76
+ opacity:1;
77
+ }
78
+ @media (hover: hover){
79
+ .group:hover .headerActions{
80
+ pointer-events:auto;
81
+ opacity:1;
82
+ }
83
+ }
77
84
 
78
85
  .groupDragPreview{
79
- cursor:grabbing;
80
86
  container-type:inline-size;
81
87
  border-radius:var(--sn-density-radius-2xs, var(--sn-platform-comfort-radius-2xs, var(--sn-primitive-dimension-4, 4px)));
82
88
  }
@@ -119,7 +125,6 @@
119
125
 
120
126
  .groupBody{
121
127
  display:grid;
122
- grid-template-columns:repeat(3, minmax(auto, 1fr));
123
128
  gap:var(--sn-primitive-dimension-4, 4px);
124
129
  }
125
130
  .groupBody:not([data-subcategory-body]){
@@ -128,10 +133,8 @@
128
133
  .groupBody:not([data-show-description]){
129
134
  gap:0;
130
135
  }
131
- @container (width <= 728px){
132
- .groupBody:not([data-mobile]){
133
- grid-template-columns:repeat(2, minmax(auto, 1fr));
134
- }
136
+ .groupBody:not([data-mobile]){
137
+ grid-template-columns:repeat(auto-fill, minmax(240px, 1fr));
135
138
  }
136
139
  .groupBody[data-mobile]{
137
140
  grid-template-columns:repeat(1, minmax(200px, 1fr));
@@ -21,6 +21,21 @@
21
21
  gap:inherit;
22
22
  }
23
23
 
24
+ .rightTop{
25
+ width:100%;
26
+ min-width:0;
27
+ }
28
+ .rightTop:not([data-mobile]){
29
+ display:grid;
30
+ grid-template-columns:repeat(auto-fit, minmax(max(252px, (100% - var(--sn-primitive-dimension-4, 4px)) / 2), 1fr));
31
+ gap:var(--sn-primitive-dimension-4, 4px);
32
+ }
33
+ .rightTop[data-mobile]{
34
+ display:flex;
35
+ flex-direction:column;
36
+ gap:var(--sn-primitive-dimension-8, 8px);
37
+ }
38
+
24
39
  .noData{
25
40
  flex:1 1 auto;
26
41
  place-self:center center;
@@ -1,2 +1,2 @@
1
1
  import { MainMenuProps } from '../../types';
2
- export declare function MenuDesktop({ open, setOpen, settingItems, platformGroups, segments, segmentPrefs, activeSegmentId, onActiveSegmentChange, onSegmentOrderChange, onSegmentExpandedChange, onSegmentServiceClick, favorite, search, preferences, logo, rightTop, leftTop, leftBottom, defaultWidth, onWidthChangeEnd, draggerTooltip, loading, }: MainMenuProps): import("react/jsx-runtime").JSX.Element;
2
+ export declare function MenuDesktop({ open, setOpen, settingItems, platformGroups, segments, segmentPrefs, activeSegmentId, onActiveSegmentChange, onSegmentOrderChange, onSegmentExpandedChange, onToggleAllGroupsExpanded, onSegmentServiceClick, favorite, search, preferences, logo, rightTop, leftTop, leftBottom, defaultWidth, onWidthChangeEnd, draggerTooltip, loading, }: MainMenuProps): import("react/jsx-runtime").JSX.Element;
@@ -21,7 +21,7 @@ const MountAnimation_1 = require("../MountAnimation");
21
21
  const Search_1 = require("../Search");
22
22
  const constants_2 = require("./constants");
23
23
  const styles_module_scss_1 = __importDefault(require('./styles.module.css'));
24
- function MenuDesktop({ open = false, setOpen, settingItems, platformGroups, segments, segmentPrefs, activeSegmentId, onActiveSegmentChange, onSegmentOrderChange, onSegmentExpandedChange, onSegmentServiceClick, favorite, search, preferences, logo, rightTop, leftTop, leftBottom, defaultWidth = constants_2.MENU_WIDTH_MAX, onWidthChangeEnd, draggerTooltip, loading, }) {
24
+ function MenuDesktop({ open = false, setOpen, settingItems, platformGroups, segments, segmentPrefs, activeSegmentId, onActiveSegmentChange, onSegmentOrderChange, onSegmentExpandedChange, onToggleAllGroupsExpanded, onSegmentServiceClick, favorite, search, preferences, logo, rightTop, leftTop, leftBottom, defaultWidth = constants_2.MENU_WIDTH_DEFAULT, onWidthChangeEnd, draggerTooltip, loading, }) {
25
25
  const { scrollRef, searchRef, resultItems } = (0, useMenuItems_1.useMenuItems)({
26
26
  segments,
27
27
  search,
@@ -56,12 +56,12 @@ function MenuDesktop({ open = false, setOpen, settingItems, platformGroups, segm
56
56
  const handleCloseDrawer = (0, react_1.useCallback)(() => {
57
57
  setOpen?.(false);
58
58
  }, [setOpen]);
59
- const menu = ((0, jsx_runtime_1.jsxs)("div", { className: styles_module_scss_1.default.menu, children: [(0, jsx_runtime_1.jsxs)("div", { className: styles_module_scss_1.default.menuHeader, children: [(0, jsx_runtime_1.jsx)(MenuHeaderBrand_1.MenuHeaderBrand, { logo: logo, onClose: handleCloseDrawer, className: styles_module_scss_1.default.menuHeaderBrand }), isNeedRightBlock && search && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(divider_1.Divider, { orientation: 'vertical' }), (0, jsx_runtime_1.jsx)(Search_1.Search, { ...search, ref: searchRef })] }))] }), (0, jsx_runtime_1.jsx)(divider_1.Divider, {}), (0, jsx_runtime_1.jsxs)("div", { className: styles_module_scss_1.default.menuBody, children: [(0, jsx_runtime_1.jsxs)(MountAnimation_1.MountAnimation, { className: styles_module_scss_1.default.left, "data-test-id": constants_1.TEST_IDS.mainMenu.left, type: 'slide-right', children: [leftTop && (0, jsx_runtime_1.jsx)("div", { className: styles_module_scss_1.default.leftTop, children: leftTop }), isNeedRightBlock && favorite && (0, jsx_runtime_1.jsx)(Favorites_1.Favorites, { favorite: favorite, servicesById: servicesById }), hasBottomItems && (0, jsx_runtime_1.jsx)(MenuBottom_1.MenuBottom, { settingItems: settingItems, leftBottom: leftBottom })] }), isNeedRightBlock && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(MountAnimation_1.MountAnimation, { type: 'fade-in', children: (0, jsx_runtime_1.jsx)(divider_1.Divider, { orientation: 'vertical' }) }), (0, jsx_runtime_1.jsx)("div", { className: styles_module_scss_1.default.right, "data-test-id": constants_1.TEST_IDS.mainMenu.right, children: (0, jsx_runtime_1.jsx)(scroll_1.Scroll, { paddingAbsolute: true, className: styles_module_scss_1.default.scroll, ref: scrollRef, barHideStrategy: 'never', overflow: { x: 'hidden' }, children: (0, jsx_runtime_1.jsx)(Content_1.Content, { className: styles_module_scss_1.default.rightContent, searchValue: search?.value, rightTop: rightTop, favorite: favorite, segments: segments, searchGroups: resultItems, segmentPrefs: segmentPrefs, activeSegmentId: activeSegmentId, onActiveSegmentChange: onActiveSegmentChange, onSegmentOrderChange: onSegmentOrderChange, onSegmentExpandedChange: onSegmentExpandedChange, onSegmentServiceClick: onSegmentServiceClick, preferences: preferences, loading: loading }) }) })] }))] })] }));
59
+ const menu = ((0, jsx_runtime_1.jsxs)("div", { className: styles_module_scss_1.default.menu, children: [(0, jsx_runtime_1.jsxs)("div", { className: styles_module_scss_1.default.menuHeader, children: [(0, jsx_runtime_1.jsx)(MenuHeaderBrand_1.MenuHeaderBrand, { logo: logo, onClose: handleCloseDrawer, className: styles_module_scss_1.default.menuHeaderBrand }), isNeedRightBlock && search && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(divider_1.Divider, { orientation: 'vertical' }), (0, jsx_runtime_1.jsx)(Search_1.Search, { ...search, ref: searchRef })] }))] }), (0, jsx_runtime_1.jsx)(divider_1.Divider, {}), (0, jsx_runtime_1.jsxs)("div", { className: styles_module_scss_1.default.menuBody, children: [(0, jsx_runtime_1.jsxs)(MountAnimation_1.MountAnimation, { className: styles_module_scss_1.default.left, "data-test-id": constants_1.TEST_IDS.mainMenu.left, type: 'slide-right', children: [leftTop && (0, jsx_runtime_1.jsx)("div", { className: styles_module_scss_1.default.leftTop, children: leftTop }), isNeedRightBlock && favorite && (0, jsx_runtime_1.jsx)(Favorites_1.Favorites, { favorite: favorite, servicesById: servicesById }), hasBottomItems && (0, jsx_runtime_1.jsx)(MenuBottom_1.MenuBottom, { settingItems: settingItems, leftBottom: leftBottom })] }), isNeedRightBlock && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(MountAnimation_1.MountAnimation, { type: 'fade-in', children: (0, jsx_runtime_1.jsx)(divider_1.Divider, { orientation: 'vertical' }) }), (0, jsx_runtime_1.jsx)("div", { className: styles_module_scss_1.default.right, "data-test-id": constants_1.TEST_IDS.mainMenu.right, children: (0, jsx_runtime_1.jsx)(scroll_1.Scroll, { paddingAbsolute: true, className: styles_module_scss_1.default.scroll, ref: scrollRef, barHideStrategy: 'never', overflow: { x: 'hidden' }, children: (0, jsx_runtime_1.jsx)(Content_1.Content, { className: styles_module_scss_1.default.rightContent, searchValue: search?.value, rightTop: rightTop, favorite: favorite, segments: segments, searchGroups: resultItems, segmentPrefs: segmentPrefs, activeSegmentId: activeSegmentId, onActiveSegmentChange: onActiveSegmentChange, onSegmentOrderChange: onSegmentOrderChange, onSegmentExpandedChange: onSegmentExpandedChange, onSegmentServiceClick: onSegmentServiceClick, onToggleAllGroupsExpanded: onToggleAllGroupsExpanded, preferences: preferences, loading: loading }) }) })] }))] })] }));
60
60
  return ((0, jsx_runtime_1.jsx)(drawer_1.DrawerCustom, { open: open, onClose: handleCloseDrawer, width: isNeedRightBlock ? 'm' : 's', position: 'left', className: styles_module_scss_1.default.drawer, rootClassName: styles_module_scss_1.default.drawerRoot, "data-test-id": constants_1.TEST_IDS.mainMenu.drawer, "data-small": !isNeedRightBlock || undefined, disableMotions: true, showButtonClosed: false, resizable: isNeedRightBlock
61
61
  ? {
62
62
  min: constants_2.MENU_WIDTH_MIN,
63
- max: constants_2.MENU_WIDTH_MAX,
64
- default: Math.min(Math.max(defaultWidth, constants_2.MENU_WIDTH_MIN), constants_2.MENU_WIDTH_MAX),
63
+ max: 'full',
64
+ default: defaultWidth,
65
65
  onResizeEnd: onWidthChangeEnd,
66
66
  draggerTooltip,
67
67
  }
@@ -1,3 +1,3 @@
1
1
  export declare const MENU_WIDTH_STORAGE_KEY = "cloud-ru-main-menu-user-width";
2
2
  export declare const MENU_WIDTH_MIN: number;
3
- export declare const MENU_WIDTH_MAX: number;
3
+ export declare const MENU_WIDTH_DEFAULT: number;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.MENU_WIDTH_MAX = exports.MENU_WIDTH_MIN = exports.MENU_WIDTH_STORAGE_KEY = void 0;
3
+ exports.MENU_WIDTH_DEFAULT = exports.MENU_WIDTH_MIN = exports.MENU_WIDTH_STORAGE_KEY = void 0;
4
4
  exports.MENU_WIDTH_STORAGE_KEY = 'cloud-ru-main-menu-user-width';
5
5
  // паддинг справа 24px у дровера нужно компенсировать
6
- exports.MENU_WIDTH_MIN = 960 + 24;
7
- exports.MENU_WIDTH_MAX = 1208 + 24;
6
+ exports.MENU_WIDTH_MIN = 630 + 24;
7
+ exports.MENU_WIDTH_DEFAULT = 1208 + 24;
@@ -1,4 +1,7 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.useMainMenuDndOverlay = useMainMenuDndOverlay;
4
7
  exports.useMainMenuDnd = useMainMenuDnd;
@@ -11,6 +14,7 @@ const portal_context_1 = require("@cloud-ru/ds-portal-context");
11
14
  const react_1 = require("react");
12
15
  const react_dom_1 = require("react-dom");
13
16
  const ServiceCard_1 = require("../helperComponents/ServiceCard");
17
+ const styles_module_scss_1 = __importDefault(require('../styles.module.css'));
14
18
  const utils_1 = require("../utils");
15
19
  const restrictGroupDragToVerticalAxis = args => {
16
20
  if (args.active?.id != null && (0, utils_1.isServiceSourceDragId)(args.active.id)) {
@@ -87,6 +91,14 @@ function useMainMenuDnd({ favorite, servicesById, showDescription }) {
87
91
  }
88
92
  function MainMenuDndContext({ children, sensors, modifiers, collisionDetection, onDragStart, onDragEnd, onDragCancel, dragOverlay, overlayContextValue, }) {
89
93
  const portalContextRef = (0, portal_context_1.usePortalContext)();
94
+ const isDragging = Boolean(dragOverlay);
95
+ (0, react_1.useEffect)(() => {
96
+ if (!isDragging)
97
+ return;
98
+ /* Для предотвращения случайных взаимодействий с любыми другими элементами при перетаскивании */
99
+ document.body.classList.add(styles_module_scss_1.default.dragging);
100
+ return () => document.body.classList.remove(styles_module_scss_1.default.dragging);
101
+ }, [isDragging]);
90
102
  // `DragOverlay` рендерит `position: fixed` без собственного портала. Drawer-обёртка
91
103
  // (`.snack-rc-drawer-content-wrapper`) держит `will-change: transform`, а это, как и
92
104
  // настоящий transform, создаёт containing block для fixed-потомков — оверлей резолвится
@@ -0,0 +1,8 @@
1
+ .dragging,
2
+ .dragging *{
3
+ cursor:grabbing !important;
4
+ }
5
+
6
+ .dragging *{
7
+ pointer-events:none !important;
8
+ }
@@ -240,7 +240,7 @@ export type MainMenuSettingsItem = Pick<InnerLink, 'id' | 'label' | 'icon' | 'on
240
240
  /** Разделитель до/после пункта. */
241
241
  divider?: 'before' | 'after';
242
242
  };
243
- export type MainMenuProps = Pick<ContentProps, 'segments' | 'searchGroups' | 'segmentPrefs' | 'activeSegmentId' | 'onActiveSegmentChange' | 'onSegmentOrderChange' | 'onSegmentExpandedChange' | 'onSegmentServiceClick' | 'favorite' | 'preferences' | 'loading' | 'rightTop'> & {
243
+ export type MainMenuProps = Pick<ContentProps, 'segments' | 'searchGroups' | 'segmentPrefs' | 'activeSegmentId' | 'onActiveSegmentChange' | 'onSegmentOrderChange' | 'onSegmentExpandedChange' | 'onToggleAllGroupsExpanded' | 'onSegmentServiceClick' | 'favorite' | 'preferences' | 'loading' | 'rightTop'> & {
244
244
  /** Кнопка открытия меню недоступна для клика. */
245
245
  disabled?: boolean;
246
246
  /**
@@ -169,6 +169,7 @@
169
169
 
170
170
  .promoTag{
171
171
  cursor:inherit;
172
+ flex-shrink:0;
172
173
  }
173
174
  .root{
174
175
  display:flex;
@@ -300,6 +301,7 @@
300
301
  outline:none;
301
302
  }
302
303
  .headerActions[data-always-visible]{
304
+ pointer-events:auto;
303
305
  opacity:1;
304
306
  }
305
307
 
@@ -355,20 +357,25 @@
355
357
  animation:none;
356
358
  }
357
359
  }
358
- .group[data-drag-preview]{
359
- cursor:grabbing;
360
- }
361
360
  .group[data-drag-preview] .header{
362
- cursor:grabbing;
363
361
  background-color:var(--sn-theme-color-neutral-decorTransparent, var(--sn-brand-color-neutral-transparent-forLightMode, rgba(136, 146, 170, 0.0784313725)));
364
362
  }
365
363
  .group[data-drag-preview] .header .headerActions{
366
364
  pointer-events:auto;
367
365
  opacity:1;
368
366
  }
367
+ .group:has(:focus-visible) .headerActions{
368
+ pointer-events:auto;
369
+ opacity:1;
370
+ }
371
+ @media (hover: hover){
372
+ .group:hover .headerActions{
373
+ pointer-events:auto;
374
+ opacity:1;
375
+ }
376
+ }
369
377
 
370
378
  .groupDragPreview{
371
- cursor:grabbing;
372
379
  container-type:inline-size;
373
380
  border-radius:var(--sn-density-radius-2xs, var(--sn-platform-comfort-radius-2xs, var(--sn-primitive-dimension-4, 4px)));
374
381
  }
@@ -411,7 +418,6 @@
411
418
 
412
419
  .groupBody{
413
420
  display:grid;
414
- grid-template-columns:repeat(3, minmax(auto, 1fr));
415
421
  gap:var(--sn-primitive-dimension-4, 4px);
416
422
  }
417
423
  .groupBody:not([data-subcategory-body]){
@@ -420,10 +426,8 @@
420
426
  .groupBody:not([data-show-description]){
421
427
  gap:0;
422
428
  }
423
- @container (width <= 728px){
424
- .groupBody:not([data-mobile]){
425
- grid-template-columns:repeat(2, minmax(auto, 1fr));
426
- }
429
+ .groupBody:not([data-mobile]){
430
+ grid-template-columns:repeat(auto-fill, minmax(240px, 1fr));
427
431
  }
428
432
  .groupBody[data-mobile]{
429
433
  grid-template-columns:repeat(1, minmax(200px, 1fr));
@@ -575,6 +579,21 @@
575
579
  gap:inherit;
576
580
  }
577
581
 
582
+ .rightTop{
583
+ width:100%;
584
+ min-width:0;
585
+ }
586
+ .rightTop:not([data-mobile]){
587
+ display:grid;
588
+ grid-template-columns:repeat(auto-fit, minmax(max(252px, (100% - var(--sn-primitive-dimension-4, 4px)) / 2), 1fr));
589
+ gap:var(--sn-primitive-dimension-4, 4px);
590
+ }
591
+ .rightTop[data-mobile]{
592
+ display:flex;
593
+ flex-direction:column;
594
+ gap:var(--sn-primitive-dimension-8, 8px);
595
+ }
596
+
578
597
  .noData{
579
598
  flex:1 1 auto;
580
599
  place-self:center center;
@@ -939,6 +958,14 @@
939
958
  .staticCard{
940
959
  position:relative;
941
960
  }
961
+ .dragging,
962
+ .dragging *{
963
+ cursor:grabbing !important;
964
+ }
965
+
966
+ .dragging *{
967
+ pointer-events:none !important;
968
+ }
942
969
  .container{
943
970
  display:flex;
944
971
  align-items:center;
@@ -1,2 +1,2 @@
1
1
  import { MainMenuProps } from './types.js';
2
- export declare function MainMenu({ open: openProp, setOpen: setOpenProp, settingItems, platformGroups, logo, leftTop, leftBottom, rightTop, segments, segmentPrefs, activeSegmentId, onActiveSegmentChange, onSegmentOrderChange, onSegmentExpandedChange, onSegmentServiceClick, favorite, search, preferences, disabled, defaultWidth, onWidthChangeEnd, draggerTooltip, loading, }: MainMenuProps): import("react/jsx-runtime").JSX.Element;
2
+ export declare function MainMenu({ open: openProp, setOpen: setOpenProp, settingItems, platformGroups, logo, leftTop, leftBottom, rightTop, segments, segmentPrefs, activeSegmentId, onActiveSegmentChange, onSegmentOrderChange, onSegmentExpandedChange, onToggleAllGroupsExpanded, onSegmentServiceClick, favorite, search, preferences, disabled, defaultWidth, onWidthChangeEnd, draggerTooltip, loading, }: MainMenuProps): import("react/jsx-runtime").JSX.Element;
@@ -8,7 +8,7 @@ import { headerLocale } from '../../locale/index.js';
8
8
  import { HeaderButton } from '../HeaderButton/index.js';
9
9
  import { MenuDesktop } from './helperComponents/MenuDesktop/index.js';
10
10
  import { MenuMobile } from './helperComponents/MenuMobile/index.js';
11
- export function MainMenu({ open: openProp, setOpen: setOpenProp, settingItems, platformGroups, logo, leftTop, leftBottom, rightTop, segments, segmentPrefs, activeSegmentId, onActiveSegmentChange, onSegmentOrderChange, onSegmentExpandedChange, onSegmentServiceClick, favorite, search, preferences, disabled, defaultWidth, onWidthChangeEnd, draggerTooltip, loading, }) {
11
+ export function MainMenu({ open: openProp, setOpen: setOpenProp, settingItems, platformGroups, logo, leftTop, leftBottom, rightTop, segments, segmentPrefs, activeSegmentId, onActiveSegmentChange, onSegmentOrderChange, onSegmentExpandedChange, onToggleAllGroupsExpanded, onSegmentServiceClick, favorite, search, preferences, disabled, defaultWidth, onWidthChangeEnd, draggerTooltip, loading, }) {
12
12
  const { t } = headerLocale.useTranslations();
13
13
  const [open = false, setOpen] = useValueControl({ value: openProp, onChange: setOpenProp });
14
14
  const searchValue = search?.value;
@@ -22,5 +22,5 @@ export function MainMenu({ open: openProp, setOpen: setOpenProp, settingItems, p
22
22
  }, [setOpen]);
23
23
  const isMobile = useMobileLayout();
24
24
  const MenuComponent = isMobile ? MenuMobile : MenuDesktop;
25
- return (_jsxs(_Fragment, { children: [_jsx(HeaderButton, { tooltip: open ? undefined : { tip: t('services') }, isMobile: isMobile, disabled: disabled, icon: _jsx(MainMenuSVG, {}), onClick: handleOpen, "data-test-id": TEST_IDS.mainMenu.drawerButton }), _jsx(MenuComponent, { settingItems: settingItems, segments: segments, segmentPrefs: segmentPrefs, activeSegmentId: activeSegmentId, onActiveSegmentChange: onActiveSegmentChange, onSegmentOrderChange: onSegmentOrderChange, onSegmentExpandedChange: onSegmentExpandedChange, onSegmentServiceClick: onSegmentServiceClick, platformGroups: platformGroups, search: search, logo: logo, leftTop: leftTop, leftBottom: leftBottom, rightTop: rightTop, favorite: favorite, open: open, setOpen: setOpen, preferences: preferences, defaultWidth: defaultWidth, onWidthChangeEnd: onWidthChangeEnd, draggerTooltip: draggerTooltip, loading: loading })] }));
25
+ return (_jsxs(_Fragment, { children: [_jsx(HeaderButton, { tooltip: open ? undefined : { tip: t('services') }, isMobile: isMobile, disabled: disabled, icon: _jsx(MainMenuSVG, {}), onClick: handleOpen, "data-test-id": TEST_IDS.mainMenu.drawerButton }), _jsx(MenuComponent, { settingItems: settingItems, segments: segments, segmentPrefs: segmentPrefs, activeSegmentId: activeSegmentId, onActiveSegmentChange: onActiveSegmentChange, onSegmentOrderChange: onSegmentOrderChange, onSegmentExpandedChange: onSegmentExpandedChange, onSegmentServiceClick: onSegmentServiceClick, onToggleAllGroupsExpanded: onToggleAllGroupsExpanded, platformGroups: platformGroups, search: search, logo: logo, leftTop: leftTop, leftBottom: leftBottom, rightTop: rightTop, favorite: favorite, open: open, setOpen: setOpen, preferences: preferences, defaultWidth: defaultWidth, onWidthChangeEnd: onWidthChangeEnd, draggerTooltip: draggerTooltip, loading: loading })] }));
26
26
  }
@@ -70,4 +70,5 @@
70
70
 
71
71
  .promoTag{
72
72
  cursor:inherit;
73
+ flex-shrink:0;
73
74
  }
@@ -36,6 +36,10 @@ export type ContentProps = {
36
36
  * (без id синтетической группы избранного).
37
37
  */
38
38
  onSegmentExpandedChange?(segmentId: string, expandedGroupIds: string[]): void;
39
+ /**
40
+ * Колбэк смены всех групп раскрытых.
41
+ */
42
+ onToggleAllGroupsExpanded?(action: 'collapseAll' | 'expandAll'): void;
39
43
  /**
40
44
  * Колбэк клика по карточке сервиса в сегменте.
41
45
  */
@@ -63,4 +67,4 @@ export type ContentProps = {
63
67
  /** Флаг загрузки данных */
64
68
  loading?: boolean;
65
69
  };
66
- export declare function Content({ searchValue, search, rightTop, segments, searchGroups, segmentPrefs, activeSegmentId, onActiveSegmentChange, onSegmentOrderChange, onSegmentExpandedChange, onSegmentServiceClick, className, footer, favorite, isMobile, preferences, loading, }: ContentProps): import("react/jsx-runtime").JSX.Element;
70
+ export declare function Content({ searchValue, search, rightTop, segments, searchGroups, segmentPrefs, activeSegmentId, onActiveSegmentChange, onSegmentOrderChange, onSegmentExpandedChange, onSegmentServiceClick, onToggleAllGroupsExpanded, className, footer, favorite, isMobile, preferences, loading, }: ContentProps): import("react/jsx-runtime").JSX.Element;
@@ -20,7 +20,7 @@ import { useContentSegmentsSortable } from './hooks/useContentSegmentsSortable.j
20
20
  import { useProgressiveCount } from './hooks/useProgressiveCount.js';
21
21
  import { useSegmentDnd } from './hooks/useSegmentDnd.js';
22
22
  import styles from './styles.module.css';
23
- export function Content({ searchValue, search, rightTop, segments, searchGroups = EMPTY_ARRAY, segmentPrefs, activeSegmentId, onActiveSegmentChange, onSegmentOrderChange, onSegmentExpandedChange, onSegmentServiceClick, className, footer, favorite, isMobile, preferences, loading, }) {
23
+ export function Content({ searchValue, search, rightTop, segments, searchGroups = EMPTY_ARRAY, segmentPrefs, activeSegmentId, onActiveSegmentChange, onSegmentOrderChange, onSegmentExpandedChange, onSegmentServiceClick, onToggleAllGroupsExpanded, className, footer, favorite, isMobile, preferences, loading, }) {
24
24
  const { t } = headerLocale.useTranslations();
25
25
  const showDescription = useDeferredValue(preferences?.showDescription.value ?? false);
26
26
  const segmentPrefsById = useMemo(() => new Map((segmentPrefs ?? []).map(prefs => [prefs.id, prefs])), [segmentPrefs]);
@@ -76,13 +76,14 @@ export function Content({ searchValue, search, rightTop, segments, searchGroups
76
76
  const visibleGroupIds = useMemo(() => visibleGroups.map(({ id }) => id), [visibleGroups]);
77
77
  const allGroupsExpanded = visibleGroups.length > 0 && visibleGroupIds.every(id => expandedIdsSet.has(id));
78
78
  const handleToggleAllGroupsExpanded = useCallback(() => {
79
+ onToggleAllGroupsExpanded?.(allGroupsExpanded ? 'collapseAll' : 'expandAll');
79
80
  if (allGroupsExpanded) {
80
81
  const visibleIdsSet = new Set(visibleGroupIds);
81
82
  onExpandedChange(expandedIds.filter(id => !visibleIdsSet.has(id)));
82
83
  return;
83
84
  }
84
85
  onExpandedChange([...new Set([...expandedIds, ...visibleGroupIds])]);
85
- }, [allGroupsExpanded, expandedIds, onExpandedChange, visibleGroupIds]);
86
+ }, [allGroupsExpanded, expandedIds, onExpandedChange, visibleGroupIds, onToggleAllGroupsExpanded]);
86
87
  const cardsContext = useMemo(() => ({
87
88
  showDescription,
88
89
  isMobile,
@@ -110,5 +111,5 @@ export function Content({ searchValue, search, rightTop, segments, searchGroups
110
111
  appearance: 'neutral',
111
112
  }, content: isSearching ? t('noDataFound') : t('noData'), "data-test-id": isSearching ? TEST_IDS.noDataFound : TEST_IDS.noData, "data-mobile": isMobile || undefined, className: styles.noData }));
112
113
  })();
113
- return (_jsxs(_Fragment, { children: [search, _jsxs("div", { className: cn(styles.content, className), "data-mobile": isMobile || undefined, "data-empty": (!loading && !hasCards) || undefined, children: [!isSearching && (_jsx(_Fragment, { children: _jsxs(MountAnimation, { type: mountAnimationType, className: styles.top, children: [_jsx(ContentToolbar, { segment: segmentId, onSegmentChange: setSegmentId, segmentItems: segmentItems, allGroupsExpanded: allGroupsExpanded, onToggleAllGroupsExpanded: handleToggleAllGroupsExpanded, preferences: preferences, isMobile: isMobile, loading: loading }), rightTop] }) })), cards, footer] })] }));
114
+ return (_jsxs(_Fragment, { children: [search, _jsxs("div", { className: cn(styles.content, className), "data-mobile": isMobile || undefined, "data-empty": (!loading && !hasCards) || undefined, children: [!isSearching && (_jsx(_Fragment, { children: _jsxs(MountAnimation, { type: mountAnimationType, className: styles.top, children: [_jsx(ContentToolbar, { segment: segmentId, onSegmentChange: setSegmentId, segmentItems: segmentItems, allGroupsExpanded: allGroupsExpanded, onToggleAllGroupsExpanded: handleToggleAllGroupsExpanded, preferences: preferences, isMobile: isMobile, loading: loading }), _jsx("div", { className: styles.rightTop, "data-mobile": isMobile || undefined, children: rightTop })] }) })), cards, footer] })] }));
114
115
  }
@@ -1,8 +1 @@
1
- import { DraggableAttributes, DraggableSyntheticListeners } from '@dnd-kit/core';
2
- export type SortableGroupDragHandleProps = {
3
- /** ARIA-атрибуты `dnd-kit` draggable-элемента. */
4
- attributes?: DraggableAttributes;
5
- /** Обработчики событий `dnd-kit` для инициации перетаскивания. */
6
- listeners?: DraggableSyntheticListeners;
7
- };
8
- export declare function SortableGroupDragHandle({ attributes, listeners }: SortableGroupDragHandleProps): import("react/jsx-runtime").JSX.Element;
1
+ export declare function SortableGroupDragHandle(): import("react/jsx-runtime").JSX.Element;
@@ -3,7 +3,7 @@ import { DragDropSVG } from '@cloud-ru/ds-icons/interface/system';
3
3
  import { stopEventPropagation } from '@cloud-ru/ds-utils';
4
4
  import { headerLocale } from '../../../../../../../locale/index.js';
5
5
  import styles from '../styles.module.css';
6
- export function SortableGroupDragHandle({ attributes, listeners }) {
6
+ export function SortableGroupDragHandle() {
7
7
  const { t } = headerLocale.useTranslations();
8
- return (_jsx("button", { ...attributes, ...listeners, type: 'button', className: styles.dragHandle, "aria-label": t('dragGroup'), "data-test-id": 'header__drawer-menu__group-card-drag-handle', onClick: stopEventPropagation, children: _jsx(DragDropSVG, { size: 24 }) }));
8
+ return (_jsx("button", { type: 'button', className: styles.dragHandle, "aria-label": t('dragGroup'), "data-test-id": 'header__drawer-menu__group-card-drag-handle', onClick: stopEventPropagation, children: _jsx(DragDropSVG, { size: 24 }) }));
9
9
  }
@@ -1,11 +1,15 @@
1
+ import { DraggableAttributes, DraggableSyntheticListeners } from '@dnd-kit/core';
1
2
  import { LinksGroup, LinksGroupTitle } from '../../../../../types.js';
2
- import { SortableGroupDragHandleProps } from './SortableGroupDragHandle.js';
3
3
  export type SortableGroupHeaderProps = Pick<LinksGroup, 'icon'> & {
4
4
  label: LinksGroupTitle;
5
5
  isExpanded?: boolean;
6
6
  enableServiceDrag?: boolean;
7
7
  isMobile?: boolean;
8
- } & SortableGroupDragHandleProps;
8
+ /** ARIA-атрибуты `dnd-kit` draggable-элемента. */
9
+ attributes?: DraggableAttributes;
10
+ /** Обработчики событий `dnd-kit` для инициации перетаскивания. */
11
+ listeners?: DraggableSyntheticListeners;
12
+ };
9
13
  declare function SortableGroupHeaderBase({ label, icon, isExpanded, enableServiceDrag, attributes, listeners, isMobile, }: SortableGroupHeaderProps): import("react/jsx-runtime").JSX.Element;
10
14
  export declare const SortableGroupHeader: import("react").MemoExoticComponent<typeof SortableGroupHeaderBase>;
11
15
  export {};
@@ -12,6 +12,6 @@ function SortableGroupHeaderBase({ label, icon, isExpanded, enableServiceDrag, a
12
12
  e.stopPropagation();
13
13
  label?.onClick?.(e);
14
14
  }, [label]);
15
- return (_jsxs("div", { className: styles.header, "data-expanded": isExpanded || undefined, children: [_jsx(Typography, { variant: 'title', size: 'm', className: styles.headerTitle, "data-test-id": 'header__drawer-menu__group-card-title', children: label.onClick || label.href ? (_jsx(TitleClickable, { ...(label.href ? { as: 'a', href: label.href } : { as: 'div' }), onClick: handleLabelClick, title: label.text, icon: getLinkEmblem({ icon }) })) : (label.text) }), (enableServiceDrag || !isMobile) && (_jsxs("div", { className: styles.headerActions, "data-always-visible": isMobile || undefined, children: [enableServiceDrag && _jsx(SortableGroupDragHandle, { attributes: attributes, listeners: listeners }), !isMobile && (_jsx(Button, { view: 'elevated', appearance: 'neutral', size: 's', icon: isExpanded ? _jsx(ChevronUpSVG, {}) : _jsx(ChevronDownSVG, {}), "data-test-id": 'header__drawer-menu__group-card-collapse' }))] }))] }));
15
+ return (_jsxs("div", { className: styles.header, "data-expanded": isExpanded || undefined, ...attributes, ...listeners, tabIndex: -1, children: [_jsx(Typography, { variant: 'title', size: 'm', className: styles.headerTitle, "data-test-id": 'header__drawer-menu__group-card-title', children: label.onClick || label.href ? (_jsx(TitleClickable, { ...(label.href ? { as: 'a', href: label.href } : { as: 'div' }), onClick: handleLabelClick, title: label.text, icon: getLinkEmblem({ icon }) })) : (label.text) }), (enableServiceDrag || !isMobile) && (_jsxs("div", { className: styles.headerActions, "data-always-visible": isMobile || undefined, children: [enableServiceDrag && _jsx(SortableGroupDragHandle, {}), !isMobile && (_jsx(Button, { view: 'elevated', appearance: 'neutral', size: 's', icon: isExpanded ? _jsx(ChevronUpSVG, {}) : _jsx(ChevronDownSVG, {}), "data-test-id": 'header__drawer-menu__group-card-collapse' }))] }))] }));
16
16
  }
17
17
  export const SortableGroupHeader = memo(SortableGroupHeaderBase);